alternative new version of the AppleUtility library

This commit is contained in:
Paul Davis
2015-10-17 20:46:58 -04:00
committed by Robin Gareus
parent f7e3117c3b
commit 66704eefcb
232 changed files with 52826 additions and 3 deletions

View File

@@ -0,0 +1,580 @@
/*
File: ACBaseCodec.cpp
Abstract: ACBaseCodec.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
//=============================================================================
// Includes
//=============================================================================
#include <algorithm>
#include "ACBaseCodec.h"
#include "CABundleLocker.h"
#if TARGET_OS_WIN32
#include "CAWin32StringResources.h"
#endif
//=============================================================================
// ACBaseCodec
//=============================================================================
ACBaseCodec::ACBaseCodec( AudioComponentInstance inInstance )
:
ACCodec(inInstance),
mIsInitialized(false),
mInputFormatList(),
mInputFormat(),
mOutputFormatList(),
mOutputFormat()
{
mCodecSubType = 0;
if (inInstance) GetSubType();
}
ACBaseCodec::~ACBaseCodec()
{
}
void ACBaseCodec::GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outPropertyDataSize, Boolean& outWritable)
{
switch(inPropertyID)
{
#if BUILD_ADEC_LIB
case kAudioCodecPropertyNameCFString:
case kAudioCodecPropertyFormatCFString:
case kAudioCodecPropertyManufacturerCFString:
outPropertyDataSize = 0;
outWritable = false;
break;
#else
case kAudioCodecPropertyNameCFString:
outPropertyDataSize = SizeOf32(CFStringRef);
outWritable = false;
break;
case kAudioCodecPropertyManufacturerCFString:
outPropertyDataSize = SizeOf32(CFStringRef);
outWritable = false;
break;
case kAudioCodecPropertyFormatCFString:
outPropertyDataSize = SizeOf32(CFStringRef);
outWritable = false;
break;
#endif
case kAudioCodecPropertyRequiresPacketDescription:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyMinimumNumberInputPackets :
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyMinimumNumberOutputPackets :
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyCurrentInputFormat:
outPropertyDataSize = SizeOf32(AudioStreamBasicDescription);
outWritable = true;
break;
case kAudioCodecPropertySupportedInputFormats:
case kAudioCodecPropertyInputFormatsForOutputFormat:
outPropertyDataSize = GetNumberSupportedInputFormats() * SizeOf32(AudioStreamBasicDescription);
outWritable = false;
break;
case kAudioCodecPropertyCurrentOutputFormat:
outPropertyDataSize = SizeOf32(AudioStreamBasicDescription);
outWritable = true;
break;
case kAudioCodecPropertySupportedOutputFormats:
case kAudioCodecPropertyOutputFormatsForInputFormat:
outPropertyDataSize = GetNumberSupportedOutputFormats() * SizeOf32(AudioStreamBasicDescription);
outWritable = false;
break;
case kAudioCodecPropertyMagicCookie:
outPropertyDataSize = GetMagicCookieByteSize();
outWritable = true;
break;
case kAudioCodecPropertyInputBufferSize:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyUsedInputBufferSize:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyIsInitialized:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyAvailableNumberChannels:
outPropertyDataSize = SizeOf32(UInt32) * 2; // Mono, stereo
outWritable = false;
break;
case kAudioCodecPropertyPrimeMethod:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
case kAudioCodecPropertyPrimeInfo:
outPropertyDataSize = SizeOf32(AudioCodecPrimeInfo);
outWritable = false;
break;
case kAudioCodecPropertyDoesSampleRateConversion:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = false;
break;
default:
CODEC_THROW(kAudioCodecUnknownPropertyError);
break;
};
}
void ACBaseCodec::GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData)
{
UInt32 thePacketsToGet;
switch(inPropertyID)
{
#if !BUILD_ADEC_LIB
case kAudioCodecPropertyNameCFString:
{
if (ioPropertyDataSize != SizeOf32(CFStringRef)) CODEC_THROW(kAudioCodecBadPropertySizeError);
CABundleLocker lock;
CFStringRef name = CFCopyLocalizedStringFromTableInBundle(CFSTR("unknown codec"), CFSTR("CodecNames"), GetCodecBundle(), CFSTR(""));
*(CFStringRef*)outPropertyData = name;
break;
}
case kAudioCodecPropertyManufacturerCFString:
{
if (ioPropertyDataSize != SizeOf32(CFStringRef)) CODEC_THROW(kAudioCodecBadPropertySizeError);
CABundleLocker lock;
CFStringRef name = CFCopyLocalizedStringFromTableInBundle(CFSTR("Apple, Inc."), CFSTR("CodecNames"), GetCodecBundle(), CFSTR(""));
*(CFStringRef*)outPropertyData = name;
break;
}
#else
// If called on the device these should return nothing but 0
case kAudioCodecPropertyNameCFString:
case kAudioCodecPropertyFormatCFString:
case kAudioCodecPropertyManufacturerCFString:
ioPropertyDataSize = 0;
outPropertyData = 0;
break;
#endif
case kAudioCodecPropertyRequiresPacketDescription:
if(ioPropertyDataSize == SizeOf32(UInt32))
{
*reinterpret_cast<UInt32*>(outPropertyData) = 0;
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyMinimumNumberInputPackets :
if(ioPropertyDataSize != SizeOf32(UInt32)) CODEC_THROW(kAudioCodecBadPropertySizeError);
*(UInt32*)outPropertyData = 1;
break;
case kAudioCodecPropertyMinimumNumberOutputPackets :
if(ioPropertyDataSize != SizeOf32(UInt32)) CODEC_THROW(kAudioCodecBadPropertySizeError);
*(UInt32*)outPropertyData = 1;
break;
case kAudioCodecPropertyCurrentInputFormat:
if(ioPropertyDataSize == SizeOf32(AudioStreamBasicDescription))
{
GetCurrentInputFormat(*reinterpret_cast<AudioStreamBasicDescription*>(outPropertyData));
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertySupportedInputFormats:
case kAudioCodecPropertyInputFormatsForOutputFormat:
thePacketsToGet = ioPropertyDataSize / SizeOf32(AudioStreamBasicDescription);
GetSupportedInputFormats(reinterpret_cast<AudioStreamBasicDescription*>(outPropertyData), thePacketsToGet);
ioPropertyDataSize = thePacketsToGet * SizeOf32(AudioStreamBasicDescription);
break;
case kAudioCodecPropertyCurrentOutputFormat:
if(ioPropertyDataSize == SizeOf32(AudioStreamBasicDescription))
{
GetCurrentOutputFormat(*reinterpret_cast<AudioStreamBasicDescription*>(outPropertyData));
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertySupportedOutputFormats:
case kAudioCodecPropertyOutputFormatsForInputFormat:
thePacketsToGet = ioPropertyDataSize / SizeOf32(AudioStreamBasicDescription);
GetSupportedOutputFormats(reinterpret_cast<AudioStreamBasicDescription*>(outPropertyData), thePacketsToGet);
ioPropertyDataSize = thePacketsToGet * SizeOf32(AudioStreamBasicDescription);
break;
case kAudioCodecPropertyMagicCookie:
if(ioPropertyDataSize >= GetMagicCookieByteSize())
{
GetMagicCookie(outPropertyData, ioPropertyDataSize);
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyInputBufferSize:
if(ioPropertyDataSize == SizeOf32(UInt32))
{
*reinterpret_cast<UInt32*>(outPropertyData) = GetInputBufferByteSize();
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyUsedInputBufferSize:
if(ioPropertyDataSize == SizeOf32(UInt32))
{
*reinterpret_cast<UInt32*>(outPropertyData) = GetUsedInputBufferByteSize();
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyIsInitialized:
if(ioPropertyDataSize == SizeOf32(UInt32))
{
*reinterpret_cast<UInt32*>(outPropertyData) = IsInitialized() ? 1 : 0;
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyAvailableNumberChannels:
if(ioPropertyDataSize == SizeOf32(UInt32) * 2)
{
(reinterpret_cast<UInt32*>(outPropertyData))[0] = 1;
(reinterpret_cast<UInt32*>(outPropertyData))[1] = 2;
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyPrimeMethod:
if(ioPropertyDataSize == SizeOf32(UInt32))
{
*reinterpret_cast<UInt32*>(outPropertyData) = (UInt32)kAudioCodecPrimeMethod_None;
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyPrimeInfo:
if(ioPropertyDataSize == SizeOf32(AudioCodecPrimeInfo) )
{
(reinterpret_cast<AudioCodecPrimeInfo*>(outPropertyData))->leadingFrames = 0;
(reinterpret_cast<AudioCodecPrimeInfo*>(outPropertyData))->trailingFrames = 0;
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyDoesSampleRateConversion:
if(ioPropertyDataSize == SizeOf32(UInt32))
{
*reinterpret_cast<UInt32*>(outPropertyData) = 0;
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
default:
CODEC_THROW(kAudioCodecUnknownPropertyError);
break;
};
}
void ACBaseCodec::SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData)
{
// No property can be set when the codec is initialized
if(mIsInitialized)
{
CODEC_THROW(kAudioCodecIllegalOperationError);
}
switch(inPropertyID)
{
case kAudioCodecPropertyCurrentInputFormat:
if(inPropertyDataSize == SizeOf32(AudioStreamBasicDescription))
{
SetCurrentInputFormat(*reinterpret_cast<const AudioStreamBasicDescription*>(inPropertyData));
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyCurrentOutputFormat:
if(inPropertyDataSize == SizeOf32(AudioStreamBasicDescription))
{
SetCurrentOutputFormat(*reinterpret_cast<const AudioStreamBasicDescription*>(inPropertyData));
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
case kAudioCodecPropertyMagicCookie:
SetMagicCookie(inPropertyData, inPropertyDataSize);
break;
case kAudioCodecPropertyMinimumNumberOutputPackets :
case kAudioCodecPropertyMinimumNumberInputPackets :
case kAudioCodecPropertyInputBufferSize:
case kAudioCodecPropertyNameCFString:
case kAudioCodecPropertyManufacturerCFString:
case kAudioCodecPropertyFormatCFString:
case kAudioCodecPropertySupportedInputFormats:
case kAudioCodecPropertySupportedOutputFormats:
case kAudioCodecPropertyUsedInputBufferSize:
case kAudioCodecPropertyIsInitialized:
case kAudioCodecPropertyAvailableNumberChannels:
case kAudioCodecPropertyPrimeMethod:
case kAudioCodecPropertyPrimeInfo:
case kAudioCodecPropertyOutputFormatsForInputFormat:
case kAudioCodecPropertyInputFormatsForOutputFormat:
case kAudioCodecPropertyDoesSampleRateConversion:
case kAudioCodecPropertyRequiresPacketDescription:
CODEC_THROW(kAudioCodecIllegalOperationError);
break;
default:
CODEC_THROW(kAudioCodecUnknownPropertyError);
break;
};
}
void ACBaseCodec::Initialize(const AudioStreamBasicDescription* /* inInputFormat */, const AudioStreamBasicDescription* /* inOutputFormat */, const void* /* inMagicCookie */, UInt32 /* inMagicCookieByteSize */)
{
mIsInitialized = true;
}
void ACBaseCodec::Uninitialize()
{
mIsInitialized = false;
}
void ACBaseCodec::Reset()
{
}
UInt32 ACBaseCodec::GetNumberSupportedInputFormats() const
{
return (UInt32)mInputFormatList.size();
}
void ACBaseCodec::GetSupportedInputFormats(AudioStreamBasicDescription* outInputFormats, UInt32& ioNumberInputFormats) const
{
UInt32 theNumberFormats = (UInt32)mInputFormatList.size();
ioNumberInputFormats = (theNumberFormats < ioNumberInputFormats) ? theNumberFormats : ioNumberInputFormats;
FormatList::const_iterator theIterator = mInputFormatList.begin();
theNumberFormats = ioNumberInputFormats;
while((theNumberFormats > 0) && (theIterator != mInputFormatList.end()))
{
*outInputFormats = *theIterator;
++outInputFormats;
--theNumberFormats;
std::advance(theIterator, 1);
}
}
void ACBaseCodec::GetCurrentInputFormat(AudioStreamBasicDescription& outInputFormat)
{
outInputFormat = mInputFormat;
}
void ACBaseCodec::SetCurrentInputFormat(const AudioStreamBasicDescription& inInputFormat)
{
if(!mIsInitialized)
{
mInputFormat = inInputFormat;
}
else
{
CODEC_THROW(kAudioCodecStateError);
}
}
UInt32 ACBaseCodec::GetNumberSupportedOutputFormats() const
{
return (UInt32)mOutputFormatList.size();
}
void ACBaseCodec::GetSupportedOutputFormats(AudioStreamBasicDescription* outOutputFormats, UInt32& ioNumberOutputFormats) const
{
UInt32 theNumberFormats = (UInt32)mOutputFormatList.size();
ioNumberOutputFormats = (theNumberFormats < ioNumberOutputFormats) ? theNumberFormats : ioNumberOutputFormats;
FormatList::const_iterator theIterator = mOutputFormatList.begin();
theNumberFormats = ioNumberOutputFormats;
while((theNumberFormats > 0) && (theIterator != mOutputFormatList.end()))
{
*outOutputFormats = *theIterator;
++outOutputFormats;
--theNumberFormats;
std::advance(theIterator, 1);
}
}
void ACBaseCodec::GetCurrentOutputFormat(AudioStreamBasicDescription& outOutputFormat)
{
outOutputFormat = mOutputFormat;
}
void ACBaseCodec::SetCurrentOutputFormat(const AudioStreamBasicDescription& inOutputFormat)
{
if(!mIsInitialized)
{
mOutputFormat = inOutputFormat;
}
else
{
CODEC_THROW(kAudioCodecStateError);
}
}
UInt32 ACBaseCodec::GetMagicCookieByteSize() const
{
return 0;
}
void ACBaseCodec::GetMagicCookie(void* /* outMagicCookieData */, UInt32& ioMagicCookieDataByteSize) const
{
ioMagicCookieDataByteSize = 0;
}
void ACBaseCodec::SetMagicCookie(const void* /* outMagicCookieData */, UInt32 /* inMagicCookieDataByteSize */)
{
if(mIsInitialized)
{
CODEC_THROW(kAudioCodecStateError);
}
}
void ACBaseCodec::AddInputFormat(const AudioStreamBasicDescription& inInputFormat)
{
FormatList::iterator theIterator = std::find(mInputFormatList.begin(), mInputFormatList.end(), inInputFormat);
if(theIterator == mInputFormatList.end())
{
theIterator = std::lower_bound(mInputFormatList.begin(), mInputFormatList.end(), inInputFormat);
mInputFormatList.insert(theIterator, inInputFormat);
}
}
void ACBaseCodec::AddOutputFormat(const AudioStreamBasicDescription& inOutputFormat)
{
FormatList::iterator theIterator = std::find(mOutputFormatList.begin(), mOutputFormatList.end(), inOutputFormat);
if(theIterator == mOutputFormatList.end())
{
theIterator = std::lower_bound(mOutputFormatList.begin(), mOutputFormatList.end(), inOutputFormat);
mOutputFormatList.insert(theIterator, inOutputFormat);
}
}
OSType ACBaseCodec::GetSubType()
{
if (!mCodecSubType)
{
AudioComponentDescription desc = GetComponentDescription();
mCodecSubType = desc.componentSubType;
}
return mCodecSubType;
}

View File

@@ -0,0 +1,147 @@
/*
File: ACBaseCodec.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__ACBaseCodec_h__)
#define __ACBaseCodec_h__
//=============================================================================
// Includes
//=============================================================================
#include "ACCodec.h"
#include "CAStreamBasicDescription.h"
#include <vector>
#include "GetCodecBundle.h"
//=============================================================================
// ACBaseCodec
//
// An abstract subclass of ACCodec that implements all the nuts and bolts
// of the ACCodec interface, except for buffer handling. This class does
// the proper dispatching of property requests and manages the list of
// input and output formats.
//=============================================================================
class ACBaseCodec
:
public ACCodec
{
// Construction/Destruction
public:
ACBaseCodec( AudioComponentInstance inInstance );
virtual ~ACBaseCodec();
// Property Management
public:
virtual void GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outPropertyDataSize, Boolean& outWritable);
virtual void GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData);
virtual void SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData);
// Data Handling
public:
bool IsInitialized() const { return mIsInitialized; }
virtual void Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize);
virtual void Uninitialize();
virtual void Reset();
virtual UInt32 GetInputBufferByteSize() const = 0;
virtual UInt32 GetUsedInputBufferByteSize() const = 0;
protected:
virtual void ReallocateInputBuffer(UInt32 inInputBufferByteSize) = 0;
bool mIsInitialized;
// Format Management
public:
UInt32 GetNumberSupportedInputFormats() const;
void GetSupportedInputFormats(AudioStreamBasicDescription* outInputFormats, UInt32& ioNumberInputFormats) const;
void GetCurrentInputFormat(AudioStreamBasicDescription& outInputFormat);
virtual void SetCurrentInputFormat(const AudioStreamBasicDescription& inInputFormat);
UInt32 GetNumberSupportedOutputFormats() const;
void GetSupportedOutputFormats(AudioStreamBasicDescription* outOutputFormats, UInt32& ioNumberOutputFormats) const;
void GetCurrentOutputFormat(AudioStreamBasicDescription& outOutputFormat);
virtual void SetCurrentOutputFormat(const AudioStreamBasicDescription& inOutputFormat);
virtual UInt32 GetMagicCookieByteSize() const;
virtual void GetMagicCookie(void* outMagicCookieData, UInt32& ioMagicCookieDataByteSize) const;
virtual void SetMagicCookie(const void* outMagicCookieData, UInt32 inMagicCookieDataByteSize);
virtual bool ImplementsFeature(UInt32 /* feature */) const { return false; }
virtual void AppendInputBufferList(const AudioBufferList * /* ioBufferList */, UInt32& /* ioNumberPackets */, const AudioStreamPacketDescription * /* inPacketDescription */, UInt32 * /* outBytesConsumed */) { CODEC_THROW(-4); /*unimpErr*/ }
virtual UInt32 ProduceOutputBufferList(AudioBufferList * /* ioBufferList */, UInt32& /* ioNumberPackets */, AudioStreamPacketDescription * /* outPacketDescription */) { CODEC_THROW(-4); /*unimpErr*/ }
protected:
void AddInputFormat(const AudioStreamBasicDescription& inInputFormat);
void AddOutputFormat(const AudioStreamBasicDescription& inOutputFormat);
OSType GetSubType();
typedef std::vector<CAStreamBasicDescription> FormatList;
FormatList mInputFormatList;
#if TARGET_OS_WIN32
// VC 2005 screws up if this is not aligned to 8-byte boundaries
__declspec(align(8)) CAStreamBasicDescription mInputFormat;
#else
CAStreamBasicDescription mInputFormat;
#endif
FormatList mOutputFormatList;
#if TARGET_OS_WIN32
// VC 2005 screws up if this is not aligned to 8-byte boundaries
__declspec(align(8)) CAStreamBasicDescription mOutputFormat;
#else
CAStreamBasicDescription mOutputFormat;
#endif
OSType mCodecSubType;
UInt32 mPadding[3]; // Align this with 16-byte boundaries
};
#endif

View File

@@ -0,0 +1,329 @@
/*
File: ACCodec.cpp
Abstract: ACCodec.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
//=============================================================================
// Includes
//=============================================================================
#include "ACCodec.h"
//=============================================================================
// ACCodec
//=============================================================================
ACCodec::ACCodec(AudioComponentInstance inInstance) : ComponentBase(inInstance)
{
}
ACCodec::~ACCodec()
{
}
#if !CA_USE_AUDIO_PLUGIN_ONLY && !TARGET_OS_IPHONE
#if TARGET_OS_MAC
#if __LP64__
// comp instance, parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)((void*)&inParameters->params[_index + 1]);
#else
// parameters in reverse order, then comp instance
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)((void*)&inParameters->params[_nparams - 1 - _index]);
#endif
#elif TARGET_OS_WIN32
// (no comp instance), parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&inParameters->params[_index];
#endif
OSStatus ACCodec::ComponentEntryDispatch(ComponentParameters *inParameters, ACCodec *inThis)
{
OSStatus theError = kAudioCodecNoError;
try
{
switch (inParameters->what)
{
// these selectors don't use the object pointer
case kComponentOpenSelect:
case kComponentCloseSelect:
theError = ComponentBase::ComponentEntryDispatch(inParameters, inThis);
break;
case kComponentCanDoSelect:
{
switch (GetSelectorForCanDo(inParameters))
{
case kAudioCodecGetPropertyInfoSelect:
case kAudioCodecGetPropertySelect:
case kAudioCodecSetPropertySelect:
case kAudioCodecInitializeSelect:
case kAudioCodecUninitializeSelect: // was missing -- why?
case kAudioCodecAppendInputDataSelect:
case kAudioCodecProduceOutputDataSelect:
case kAudioCodecResetSelect:
theError = 1;
break;
default:
theError = ComponentBase::ComponentEntryDispatch(inParameters, inThis);
break;
}
}
break;
default:
// these selectors use the object pointer
if(inThis != NULL)
{
switch (inParameters->what)
{
case kComponentVersionSelect:
theError = inThis->Version();
break;
case kAudioCodecGetPropertyInfoSelect:
{
PARAM(AudioCodecPropertyID, inPropertyID, 0, 3);
PARAM(UInt32 *, outSize, 1, 3);
PARAM(Boolean *, outWritable, 2, 3);
UInt32 theSize = 0;
Boolean isWritable = false;
inThis->GetPropertyInfo(inPropertyID, theSize, isWritable);
if(outSize != NULL)
{
*outSize = theSize;
}
if(outWritable != NULL)
{
*outWritable = isWritable ? 1 : 0;
}
}
break;
case kAudioCodecGetPropertySelect:
{
PARAM(AudioCodecPropertyID, inPropertyID, 0, 3);
PARAM(UInt32 *, ioPropertyDataSize, 1, 3);
PARAM(void *, outPropertyData, 2, 3);
if((ioPropertyDataSize != NULL) && (outPropertyData != NULL))
{
inThis->GetProperty(inPropertyID, *ioPropertyDataSize, outPropertyData);
}
else
{
theError = kAudio_ParamError;
}
}
break;
case kAudioCodecSetPropertySelect:
{
PARAM(AudioCodecPropertyID, inPropertyID, 0, 3);
PARAM(UInt32, inPropertyDataSize, 1, 3);
PARAM(const void *, inPropertyData, 2, 3);
if(inPropertyData != NULL)
{
inThis->SetProperty(inPropertyID, inPropertyDataSize, inPropertyData);
}
else
{
theError = kAudio_ParamError;
}
}
break;
case kAudioCodecInitializeSelect:
{
PARAM(const AudioStreamBasicDescription *, inInputFormat, 0, 4);
PARAM(const AudioStreamBasicDescription *, inOutputFormat, 1, 4);
PARAM(const void *, inMagicCookie, 2, 4);
PARAM(UInt32, inMagicCookieByteSize, 3, 4);
inThis->Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
}
break;
case kAudioCodecUninitializeSelect:
{
inThis->Uninitialize();
}
break;
case kAudioCodecAppendInputDataSelect:
{
PARAM(const void *, inInputData, 0, 4);
PARAM(UInt32 *, ioInputDataByteSize, 1, 4);
PARAM(UInt32 *, ioNumberPackets, 2, 4);
PARAM(const AudioStreamPacketDescription *, inPacketDescription, 3, 4);
if((inInputData != NULL) && (ioInputDataByteSize != NULL))
{
if(ioNumberPackets != NULL)
{
inThis->AppendInputData(inInputData, *ioInputDataByteSize, *ioNumberPackets, inPacketDescription);
}
else
{
UInt32 theNumberPackets = 0;
inThis->AppendInputData(inInputData, *ioInputDataByteSize, theNumberPackets, inPacketDescription);
}
}
else
{
theError = kAudio_ParamError;
}
}
break;
case kAudioCodecProduceOutputDataSelect:
{
PARAM(void *, outOutputData, 0, 5);
PARAM(UInt32 *, ioOutputDataByteSize, 1, 5);
PARAM(UInt32 *, ioNumberPackets, 2, 5);
PARAM(AudioStreamPacketDescription *, outPacketDescription, 3, 5);
PARAM(UInt32 *, outStatus, 4, 5);
if((outOutputData != NULL) && (ioOutputDataByteSize != NULL) && (ioNumberPackets != NULL) && (outStatus != NULL))
{
*outStatus = inThis->ProduceOutputPackets(outOutputData, *ioOutputDataByteSize, *ioNumberPackets, outPacketDescription);
if(kAudioCodecProduceOutputPacketFailure == *outStatus)
{
theError = kAudio_ParamError;
}
}
else
{
theError = kAudio_ParamError;
}
}
break;
#if AC_NON_INTERLEAVED_SUPPORT
case kAudioCodecAppendInputBufferListSelect:
{
PARAM(const AudioBufferList *, inBufferList, 0, 4);
PARAM(UInt32 *, ioNumberPackets, 1, 4);
PARAM(const AudioStreamPacketDescription *, inPacketDescription, 2, 4);
PARAM(UInt32 *, outBytesConsumed, 3, 4);
if((inBufferList != NULL) && (outBytesConsumed != NULL))
{
if(ioNumberPackets != NULL)
{
inThis->AppendInputBufferList(inBufferList, *ioNumberPackets, inPacketDescription, outBytesConsumed);
}
else
{
UInt32 theNumberPackets = 0;
inThis->AppendInputBufferList(inBufferList, theNumberPackets, inPacketDescription, outBytesConsumed);
}
}
else
{
theError = kAudio_ParamError;
}
}
break;
case kAudioCodecProduceOutputBufferListSelect:
{
PARAM(AudioBufferList *, ioBufferList, 0, 4);
PARAM(UInt32 *, ioNumberPackets, 1, 4);
PARAM(AudioStreamPacketDescription *, outPacketDescription, 2, 4);
PARAM(UInt32 *, outStatus, 3, 4);
if((ioBufferList != NULL) && (ioNumberPackets != NULL) && (outStatus != NULL))
{
*outStatus = inThis->ProduceOutputBufferList(ioBufferList, *ioNumberPackets, outPacketDescription);
if(kAudioCodecProduceOutputPacketFailure == *outStatus)
{
theError = kAudio_ParamError;
}
}
else
{
theError = kAudio_ParamError;
}
}
break;
#endif // AC_NON_INTERLEAVED_SUPPORT
case kAudioCodecResetSelect:
{
inThis->Reset();
}
break;
default:
theError = badComponentSelector;
break;
};
}
else
{
theError = kAudio_ParamError;
}
break;
};
}
catch(OSStatus inErrorCode)
{
theError = inErrorCode;
}
catch(...)
{
theError = kAudioCodecUnspecifiedError;
}
return theError;
}
#endif // !CA_USE_AUDIO_PLUGIN_ONLY && !TARGET_OS_IPHONE

View File

@@ -0,0 +1,115 @@
/*
File: ACCodec.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__ACCodec_h__)
#define __ACCodec_h__
//=============================================================================
// Includes
//=============================================================================
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AudioCodec.h>
#else
#include "AudioCodec.h"
#endif
#include "ComponentBase.h"
//=============================================================================
// ACCodec
//
// A totally abstract base class for implementing components that conform to
// the AudioCodec API.
//=============================================================================
class ACCodec : public ComponentBase
{
// Construction/Destruction
public:
ACCodec(AudioComponentInstance inInstance);
virtual ~ACCodec();
#if !CA_USE_AUDIO_PLUGIN_ONLY && !TARGET_OS_IPHONE
static OSStatus ComponentEntryDispatch(ComponentParameters *p, ACCodec *This);
#endif
// Property Management
public:
virtual void GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outSize, Boolean& outWritable) = 0;
virtual void GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData) = 0;
virtual void SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData) = 0;
// Data Handling
public:
virtual void Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize) = 0;
virtual void Uninitialize() = 0;
virtual void Reset() = 0;
virtual void AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription) = 0;
virtual void AppendInputBufferList(const AudioBufferList *ioBufferList, UInt32& ioNumberPackets, const AudioStreamPacketDescription *inPacketDescription, UInt32 *outBytesConsumed) = 0;
virtual UInt32 ProduceOutputPackets(void* outOutputData, UInt32& ioOutputDataByteSize, UInt32& ioNumberPackets, AudioStreamPacketDescription* outPacketDescription) = 0;
virtual UInt32 ProduceOutputBufferList(AudioBufferList *ioBufferList, UInt32& ioNumberPackets, AudioStreamPacketDescription *outPacketDescription) = 0;
// Component Support
public:
// used internally
virtual bool ImplementsFeature(UInt32 feature) const = 0;
};
// when throwing static_cast to OSStatus so the catch will grab the error code correctly
#define CODEC_THROW(err) \
throw static_cast<OSStatus>(err)
#define CODEC_THROW_IF(cond, err) \
if(bool(cond)) CODEC_THROW(err);
#endif

View File

@@ -0,0 +1,259 @@
/*
File: ACCodecDispatchTypes.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__ACCodecDispatchTypes_h__)
#define __ACCodecDispatchTypes_h__
//=============================================================================
// Includes
//=============================================================================
// note that AudioCodec.h needs to be included prior to including this file
#if !defined(__AudioCodec_h__)
#error AudioCodec.h needs to be included prior to including this file
#endif
//=============================================================================
// Parameter Blocks for AudioCodec Component Routines
//
// Note that the arguments for all the AudioCodec component routines are
// 4 bytes in size (assuming pointers are 4 bytes). This means that even on
// Windows (where all arguments are forced into SInt32s), we can get away with
// mass casting the argument list through the appropriate paramblock structure.
// This gets around the fact that the component glue passes the arguments in
// a different order depending on the platform and therefore makes writing the
// calling glue and the dispatcher much simpler.
//=============================================================================
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif
#define AudioCodecStandardGluePBFields UInt8 componentFlags; UInt8 componentParamSize; SInt16 componentWhat
#if !TARGET_OS_WIN32
struct AudioCodecOpenGluePB {
AudioCodecStandardGluePBFields;
AudioCodec inCodec;
void* unused;
};
#else
struct AudioCodecOpenGluePB {
AudioCodecStandardGluePBFields;
AudioCodec inCodec;
};
#endif
typedef struct AudioCodecOpenGluePB AudioCodecOpenGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecGetPropertyInfoGluePB
{
AudioCodecStandardGluePBFields;
Boolean* outWritable;
UInt32* outSize;
AudioCodecPropertyID inPropertyID;
AudioCodec inCodec;
};
#else
struct AudioCodecGetPropertyInfoGluePB
{
AudioCodecStandardGluePBFields;
AudioCodecPropertyID inPropertyID;
UInt32* outSize;
Boolean* outWritable;
};
#endif
typedef struct AudioCodecGetPropertyInfoGluePB AudioCodecGetPropertyInfoGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecGetPropertyGluePB
{
AudioCodecStandardGluePBFields;
void* outPropertyData;
UInt32* ioPropertyDataSize;
AudioCodecPropertyID inPropertyID;
AudioCodec inCodec;
};
#else
struct AudioCodecGetPropertyGluePB
{
AudioCodecStandardGluePBFields;
AudioCodecPropertyID inPropertyID;
UInt32* ioPropertyDataSize;
void* outPropertyData;
};
#endif
typedef struct AudioCodecGetPropertyGluePB AudioCodecGetPropertyGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecSetPropertyGluePB
{
AudioCodecStandardGluePBFields;
const void* inPropertyData;
UInt32 inPropertyDataSize;
AudioCodecPropertyID inPropertyID;
AudioCodec inCodec;
};
#else
struct AudioCodecSetPropertyGluePB
{
AudioCodecStandardGluePBFields;
AudioCodecPropertyID inPropertyID;
UInt32 inPropertyDataSize;
const void* inPropertyData;
};
#endif
typedef struct AudioCodecSetPropertyGluePB AudioCodecSetPropertyGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecInitializeGluePB
{
AudioCodecStandardGluePBFields;
UInt32 inMagicCookieByteSize;
const void* inMagicCookie;
const AudioStreamBasicDescription* inOutputFormat;
const AudioStreamBasicDescription* inInputFormat;
AudioCodec inCodec;
};
#else
struct AudioCodecInitializeGluePB
{
AudioCodecStandardGluePBFields;
const AudioStreamBasicDescription* inInputFormat;
const AudioStreamBasicDescription* inOutputFormat;
const void* inMagicCookie;
UInt32 inMagicCookieByteSize;
};
#endif
typedef struct AudioCodecInitializeGluePB AudioCodecInitializeGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecUninitializeGluePB
{
AudioCodecStandardGluePBFields;
AudioCodec inCodec;
};
#else
struct AudioCodecUninitializeGluePB
{
AudioCodecStandardGluePBFields;
};
#endif
typedef struct AudioCodecUninitializeGluePB AudioCodecUninitializeGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecAppendInputDataGluePB
{
AudioCodecStandardGluePBFields;
const AudioStreamPacketDescription* inPacketDescription;
UInt32* ioNumberPackets;
UInt32* ioInputDataByteSize;
const void* inInputData;
AudioCodec inCodec;
};
#else
struct AudioCodecAppendInputDataGluePB
{
AudioCodecStandardGluePBFields;
const void* inInputData;
UInt32* ioInputDataByteSize;
UInt32* ioNumberPackets;
const AudioStreamPacketDescription* inPacketDescription;
};
#endif
typedef struct AudioCodecAppendInputDataGluePB AudioCodecAppendInputDataGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecProduceOutputPacketsGluePB
{
AudioCodecStandardGluePBFields;
UInt32* outStatus;
AudioStreamPacketDescription* outPacketDescription;
UInt32* ioNumberPackets;
UInt32* ioOutputDataByteSize;
void* outOutputData;
AudioCodec inCodec;
};
#else
struct AudioCodecProduceOutputPacketsGluePB
{
AudioCodecStandardGluePBFields;
void* outOutputData;
UInt32* ioOutputDataByteSize;
UInt32* ioNumberPackets;
AudioStreamPacketDescription* outPacketDescription;
UInt32* outStatus;
};
#endif
typedef struct AudioCodecProduceOutputPacketsGluePB AudioCodecProduceOutputPacketsGluePB;
#if !TARGET_OS_WIN32
struct AudioCodecResetGluePB
{
AudioCodecStandardGluePBFields;
AudioCodec inCodec;
};
#else
struct AudioCodecResetGluePB
{
AudioCodecStandardGluePBFields;
};
#endif
typedef struct AudioCodecResetGluePB AudioCodecResetGluePB;
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif
#endif

View File

@@ -0,0 +1,196 @@
/*
File: ACComponentResources.r
Abstract: ACComponentResources.r
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef GEN_MISSING
#define GEN_MISSING 0
#endif
#ifndef thng_RezTemplateVersion
#define thng_RezTemplateVersion 2
#endif
//=============================================================================
// Includes
//=============================================================================
#include "ConditionalMacros.r"
#include "MacTypes.r"
#include "Components.r"
//=============================================================================
// Platform constants for the thng resources
//=============================================================================
#if TARGET_OS_MAC && TARGET_API_MAC_OSX
#define Target_PlatformType 1000
#define Target_CodeResType 'dlle'
#define kUseDLLEResource 1
#elif TARGET_OS_WIN32
#define Target_PlatformType platformWin32
#define Target_CodeResType 'dlle'
#define kUseDLLEResource 1
#else
#define Target_PlatformType platformPowerPC
#define Target_CodeResType 'tppc'
#define kUseDLLEResource 0
#endif
#if kComponentIsThreadSafe
#ifndef cmpThreadSafeOnMac // so we don't need Panther headers to build
#define cmpThreadSafeOnMac 0x10000000
#endif
#define COMPONENT_FLAGS cmpThreadSafeOnMac
#else
#define COMPONENT_FLAGS 0
#endif
//=============================================================================
// The thng and related resources
//
// The definitions below use the following macros, all of which must be
// defined. Note that kPrimaryResourceID is used to define two 'STR '
// resources with consecutive IDs so be sure to space them at least two'
// apart. Here's a sample of how to do the defines:
//
// #define kPrimaryResourceID 128
// #define kComponentType 'aenc'
// #define kComponentSubtype 'ima4'
// #define kComponentManufacturer 'appl'
// #define kComponentFlags 0
// #define kComponentVersion 0x00010000
// #define kComponentName "Apple IMA4 Encoder"
// #define kComponentInfo "An AudioCodec that encodes linear PCM data into IMA4"
// #define kComponentEntryPoint "ACAppleIMA4EncoderEntry"
// #define kComponentPublicResourceMapType 0
// #define kComponentIsThreadSafe 1
//=============================================================================
#ifndef AC_LOCALIZED
resource 'strn' (kPrimaryResourceID, purgeable)
{
kComponentName
};
resource 'stri' (kPrimaryResourceID, purgeable)
{
kComponentInfo
};
#endif
#if !GEN_MISSING
#if kUseDLLEResource
resource 'dlle' (kPrimaryResourceID)
{
kComponentEntryPoint
};
#endif
#define kComponentRegistrationFlags componentHasMultiplePlatforms | componentDoAutoVersion | componentLoadResident
resource 'thng' (kPrimaryResourceID, kComponentName)
{
kComponentType, // Component type
kComponentSubtype, // Component subtype
kComponentManufacturer, // Component manufacturer
kComponentFlags, // Component flags
0, // Component flags mask
0, 0, // Code type, Code ID
'strn', kPrimaryResourceID, // Name resource type, resource ID
'stri', kPrimaryResourceID, // Info resource type, resource ID
0, 0, // Icon resource type, resource ID
kComponentVersion, // Component version
kComponentRegistrationFlags, // Registration flags
0, // Icon family resource ID
{ // Beginning of platform info
COMPONENT_FLAGS, // Component flags
Target_CodeResType, kPrimaryResourceID, // Code resource type, resource ID
Target_PlatformType, // Platform type
},
#if thng_RezTemplateVersion >= 2
kComponentPublicResourceMapType, kPrimaryResourceID // Resource map type, resource map ID
#endif
};
#else // GEN_MISSING
resource 'thga' (kPrimaryResourceID) {
kComponentType, // Component type
kComponentSubtype, // Component subtype
kComponentManufacturer, // Component manufacturer
kComponentFlags, // Component flags
0, // Component flags mask
0, 0, // Code type, Code ID
'strn', kPrimaryResourceID, // Name resource type, resource ID
'stri', kPrimaryResourceID, // Info resource type, resource ID
0, 0, // Icon resource type, resource ID
'miss', // Alias component type
'base', // Alias component subtype
0, // Alias component manufacturer
0, // Alias component flags
0, // Alias component flags mask
#if thng_RezTemplateVersion >= 2
kComponentPublicResourceMapType, kPrimaryResourceID, // Resource map type, resource map ID
cmpAliasNoFlags // Alias flags
#endif
};
#endif // GEN_MISSING
#undef kPrimaryResourceID
#undef kComponentType
#undef kComponentSubtype
#undef kComponentManufacturer
#undef kComponentVersion
#undef kComponentRegistrationFlags
#undef kComponentName
#undef kComponentInfo
#undef kComponentEntryPoint
#undef kComponentPublicResourceMapType
#undef Target_PlatformType
#undef Target_CodeResType
#undef kUseDLLEResource

View File

@@ -0,0 +1,73 @@
/*
File: ACConditionalMacros.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__ACConditionalMacros_h__)
#define __ACConditionalMacros_h__
//=============================================================================
// This file exists to make figuring out how to include system headers
// easier. We throw in an include of the standard ConditionalMacros too.
//=============================================================================
// TargetConditionals.h defines the bare minimum we need
#include "TargetConditionals.h"
// Determine whether or not to use framework style includes for system headers
#if !defined(AC_Use_Framework_Includes)
#if TARGET_OS_MAC && TARGET_RT_MAC_MACHO
#define AC_Use_Framework_Includes 1
#else
#define AC_Use_Framework_Includes 0
#endif
#endif
#if AC_Use_Framework_Includes
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/ConditionalMacros.h>
#else
#include "ConditionalMacros.h"
#endif
#endif

View File

@@ -0,0 +1,283 @@
/*
File: ACPlugInDispatch.cpp
Abstract: ACPlugInDispatch.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if AUDIOCODECS_SUPPORT_PLUGINS
#include "ACPlugInDispatch.h"
#include "CAXException.h"
#include "ACCodec.h"
#include <new>
#define ACPI ((AudioComponentPlugInInstance *)self)
#define ACC ((ACCodec *)&ACPI->mInstanceStorage)
static OSStatus GetPropertyInfo(void *self, AudioCodecPropertyID inPropertyID, UInt32 *outSize, Boolean *outWritable)
{
OSStatus result = noErr;
try {
UInt32 size;
Boolean writable;
ACC->GetPropertyInfo(inPropertyID, size, writable);
if (outSize) *outSize = size;
if (outWritable) *outWritable = writable;
}
COMPONENT_CATCH
return result;
}
static OSStatus GetProperty(void *self, AudioCodecPropertyID inPropertyID, UInt32 *ioPropertyDataSize, void *outPropertyData)
{
OSStatus result = noErr;
try {
ACC->GetProperty(inPropertyID, *ioPropertyDataSize, outPropertyData);
}
COMPONENT_CATCH
return result;
}
static OSStatus SetProperty(void *self, AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData)
{
OSStatus result = noErr;
try {
ACC->SetProperty(inPropertyID, inPropertyDataSize, inPropertyData);
}
COMPONENT_CATCH
return result;
}
static OSStatus Initialize(void *self, const AudioStreamBasicDescription *inInputFormat, const AudioStreamBasicDescription *inOutputFormat, const void *inMagicCookie, UInt32 inMagicCookieByteSize)
{
OSStatus result = noErr;
try {
ACC->Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
}
COMPONENT_CATCH
return result;
}
static OSStatus Uninitialize(void *self)
{
OSStatus result = noErr;
try {
ACC->Uninitialize();
}
COMPONENT_CATCH
return result;
}
static OSStatus AppendInputData(void *self, const void *inInputData, UInt32 *ioInputDataByteSize, UInt32 *ioNumberPackets, const AudioStreamPacketDescription *inPacketDescription)
{
OSStatus result = noErr;
try {
UInt32 npackets = (ioNumberPackets != NULL) ? *ioNumberPackets : 0;
ACC->AppendInputData(inInputData, *ioInputDataByteSize, npackets, inPacketDescription);
if(ioNumberPackets != NULL)
*ioNumberPackets = npackets;
}
COMPONENT_CATCH
return result;
}
static OSStatus ProduceOutputPackets(void *self, void *outOutputData, UInt32 *ioOutputDataByteSize, UInt32 *ioNumberPackets, AudioStreamPacketDescription *outPacketDescription, UInt32 *outStatus)
{
OSStatus result = noErr;
try {
*outStatus = ACC->ProduceOutputPackets(outOutputData, *ioOutputDataByteSize, *ioNumberPackets, outPacketDescription);
if (*outStatus == kAudioCodecProduceOutputPacketFailure)
result = kAudio_ParamError;
}
COMPONENT_CATCH
return result;
}
static OSStatus Reset(void *self)
{
OSStatus result = noErr;
try {
ACC->Reset();
}
COMPONENT_CATCH
return result;
}
#if AC_NON_INTERLEAVED_SUPPORT
static OSStatus AppendInputBufferList(void *self, const AudioBufferList *ioBufferList, UInt32 *inNumberPackets, const AudioStreamPacketDescription *inPacketDescription, UInt32 *outBytesConsumed)
{
OSStatus result = noErr;
try {
if((ioBufferList != NULL) && (outBytesConsumed != NULL))
{
if(inNumberPackets != NULL)
{
ACC->AppendInputBufferList(ioBufferList, *inNumberPackets, inPacketDescription, outBytesConsumed);
}
else
{
UInt32 theNumberPackets = 0;
ACC->AppendInputBufferList(ioBufferList, theNumberPackets, inPacketDescription, outBytesConsumed);
}
}
else
{
result = kAudio_ParamError;
}
}
COMPONENT_CATCH
return result;
}
static OSStatus ProduceOutputBufferList(void *self, AudioBufferList *ioBufferList, UInt32 *ioNumberPackets, AudioStreamPacketDescription *outPacketDescription, UInt32 *outStatus)
{
OSStatus result = noErr;
try {
if((ioBufferList != NULL) && (ioNumberPackets != NULL) && (outStatus != NULL))
{
*outStatus = ACC->ProduceOutputBufferList(ioBufferList, *ioNumberPackets, outPacketDescription);
if(kAudioCodecProduceOutputPacketFailure == *outStatus)
{
result = kAudio_ParamError;
}
}
else
{
result = kAudio_ParamError;
}
}
COMPONENT_CATCH
return result;
}
#endif
#if TARGET_OS_IPHONE && AUDIOCONV_HAVE_AMC
// The ACTransformerCodecBase class is the base for ALL hardware codecs.
// No need to check for ImplementFeature...
#include "ACTransformerManager.h"
#define ACTM ((ACTransformerCodecBase*)&ACPI->mInstanceStorage)
static OSStatus AcquireHardware(void *self)
{
OSStatus result = noErr;
try {
ACTM->AcquireHardware();
}
COMPONENT_CATCH
return result;
}
static OSStatus ReleaseHardware(void *self)
{
OSStatus result = noErr;
try {
ACTM->ReleaseHardware();
}
COMPONENT_CATCH
return result;
}
#endif // TARGET_OS_IPHONE && AUDIOCONV_HAVE_AMC
AudioComponentMethod AudioCodecLookup::Lookup (SInt16 selector)
{
switch (selector) {
case kAudioCodecGetPropertyInfoSelect: return (AudioComponentMethod)GetPropertyInfo;
case kAudioCodecGetPropertySelect: return (AudioComponentMethod)GetProperty;
case kAudioCodecSetPropertySelect: return (AudioComponentMethod)SetProperty;
case kAudioCodecInitializeSelect: return (AudioComponentMethod)Initialize;
case kAudioCodecUninitializeSelect: return (AudioComponentMethod)Uninitialize;
case kAudioCodecAppendInputDataSelect: return (AudioComponentMethod)AppendInputData;
case kAudioCodecProduceOutputDataSelect: return (AudioComponentMethod)ProduceOutputPackets;
case kAudioCodecResetSelect: return (AudioComponentMethod)Reset;
default:
break;
}
return NULL;
}
#if AC_NON_INTERLEAVED_SUPPORT
AudioComponentMethod AudioCodecNonInterleavedEncoderLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AudioCodecLookup::Lookup(selector);
if (method)
return method;
if (selector == kAudioCodecAppendInputBufferListSelect)
return (AudioComponentMethod)AppendInputBufferList;
return NULL;
}
AudioComponentMethod AudioCodecNonInterleavedDecoderLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AudioCodecLookup::Lookup(selector);
if (method)
return method;
if (selector == kAudioCodecProduceOutputBufferListSelect)
return (AudioComponentMethod)ProduceOutputBufferList;
return NULL;
}
#endif
#if TARGET_OS_IPHONE && AUDIOCONV_HAVE_AMC
#include "AudioCodecPriv.h"
AudioComponentMethod AudioCodecHWCodecLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AudioCodecLookup::Lookup(selector);
if (method) return method;
switch (selector) {
case kAudioCodecAcquireHardwareSelect: return (AudioComponentMethod)AcquireHardware;
case kAudioCodecReleaseHardwareSelect: return (AudioComponentMethod)ReleaseHardware;
default:
break;
}
return NULL;
}
#endif // TARGET_OS_IPHONE && AUDIOCONV_HAVE_AMC
#endif // AUDIOCODECS_SUPPORT_PLUGINS

View File

@@ -0,0 +1,88 @@
/*
File: ACPlugInDispatch.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __ACPlugInDispatch_h__
#define __ACPlugInDispatch_h__
#include "ComponentBase.h"
struct AudioCodecLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AudioCodecFactory : public APFactory<AudioCodecLookup, Implementor>
{
};
#if AC_NON_INTERLEAVED_SUPPORT
struct AudioCodecNonInterleavedEncoderLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AudioCodecNonInterleavedEncoderFactory : public APFactory<AudioCodecNonInterleavedEncoderLookup, Implementor>
{
};
struct AudioCodecNonInterleavedDecoderLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AudioCodecNonInterleavedDecoderFactory : public APFactory<AudioCodecNonInterleavedDecoderLookup, Implementor>
{
};
#endif
#if TARGET_OS_IPHONE
struct AudioCodecHWCodecLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AudioCodecHWCodecFactory : public APFactory<AudioCodecHWCodecLookup, Implementor>
{
};
#endif // TARGET_OS_IPHONE
#endif // __ACPlugInDispatch_h__

View File

@@ -0,0 +1,364 @@
/*
File: ACSimpleCodec.cpp
Abstract: ACSimpleCodec.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
//=============================================================================
// Includes
//=============================================================================
#include "ACSimpleCodec.h"
#include <string.h>
//=============================================================================
// ACSimpleCodec
//=============================================================================
static const UInt32 kBufferPad = 64; // this is used to prevent end from passing start.
ACSimpleCodec::ACSimpleCodec(UInt32 inInputBufferByteSize, AudioComponentInstance inInstance)
:
ACBaseCodec(inInstance),
mInputBuffer(NULL),
mInputBufferByteSize(inInputBufferByteSize+kBufferPad),
mInputBufferStart(0),
mInputBufferEnd(0)
{
}
ACSimpleCodec::~ACSimpleCodec()
{
delete[] mInputBuffer;
}
void ACSimpleCodec::Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize)
{
ReallocateInputBuffer(mInputBufferByteSize - kBufferPad);
// By definition CBR has this greater than 0. We must avoid a div by 0 error in AppendInputData()
// Note this will cause us to fail initialization which is intended
if (mInputFormat.mBytesPerPacket == 0)
{
CODEC_THROW(kAudioCodecUnsupportedFormatError);
}
ACBaseCodec::Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
}
void ACSimpleCodec::Uninitialize()
{
// get rid of the buffer
delete[] mInputBuffer;
mInputBuffer = NULL;
// reset the ring buffer state
mInputBufferStart = 0;
mInputBufferEnd = 0;
ACBaseCodec::Uninitialize();
}
void ACSimpleCodec::Reset()
{
// clear the entire input buffer
if (mInputBuffer) { // could be called before allocated.
memset(mInputBuffer, 0, mInputBufferByteSize);
}
// reset the ring buffer state
mInputBufferStart = 0;
mInputBufferEnd = 0;
ACBaseCodec::Reset();
}
UInt32 ACSimpleCodec::GetInputBufferByteSize() const
{
return mInputBufferByteSize - kBufferPad; // minus kBufferPad to prevent end moving past start
}
UInt32 ACSimpleCodec::GetUsedInputBufferByteSize() const
{
UInt32 theAnswer = 0;
// this object uses a ring buffer
if(mInputBufferStart <= mInputBufferEnd)
{
// the active region is contiguous
theAnswer = mInputBufferEnd - mInputBufferStart;
}
else
{
// the active region wraps around
theAnswer = (mInputBufferByteSize - mInputBufferStart) + mInputBufferEnd;
}
return theAnswer;
}
void ACSimpleCodec::AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
{
// this buffer handling code doesn't care about such things as the packet descriptions
if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
// this is a ring buffer we're dealing with, so we need to set up a few things
UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
UInt32 theMaxAvailableInputBytes = ioInputDataByteSize; // we can't consume more than we get
const Byte* theInputData = static_cast<const Byte*>(inInputData);
// >>jamesmcc: added this because ioNumberPackets was not being updated if less was taken than given.
// THIS ASSUMES CBR!
UInt32 bytesPerPacketOfInput = mInputFormat.mBytesPerPacket;
UInt32 theAvailablePacketSize = theAvailableByteSize / bytesPerPacketOfInput;
UInt32 minPacketSize = ioNumberPackets < theAvailablePacketSize ? ioNumberPackets : theAvailablePacketSize;
UInt32 minByteSize = minPacketSize * bytesPerPacketOfInput;
// we can copy only as much data as there is or up to how much space is availiable
ioNumberPackets = minPacketSize;
ioInputDataByteSize = minByteSize;
// ioInputDataByteSize had better be <= to theMaxAvailableInputBytes or we're screwed
if (ioInputDataByteSize > theMaxAvailableInputBytes)
{
CODEC_THROW(kAudioCodecStateError);
}
// <<jamesmcc
// now we have to copy the data taking into account the wrap around and where the start is
if(mInputBufferEnd + ioInputDataByteSize < mInputBufferByteSize)
{
// no wrap around here
memcpy(mInputBuffer + mInputBufferEnd, theInputData, ioInputDataByteSize);
// adjust the end point
mInputBufferEnd += ioInputDataByteSize;
}
else
{
// the copy will wrap
// copy the first part
UInt32 theBeforeWrapByteSize = mInputBufferByteSize - mInputBufferEnd;
memcpy(mInputBuffer + mInputBufferEnd, theInputData, theBeforeWrapByteSize);
// and the rest
UInt32 theAfterWrapByteSize = ioInputDataByteSize - theBeforeWrapByteSize;
memcpy(mInputBuffer, theInputData + theBeforeWrapByteSize, theAfterWrapByteSize);
// adjust the end point
mInputBufferEnd = theAfterWrapByteSize;
}
}
void ACSimpleCodec::ZeroPadInputData(UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
{
// this buffer handling code doesn't care about such things as the packet descriptions
if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
// this is a ring buffer we're dealing with, so we need to set up a few things
UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
// >>jamesmcc: added this because ioNumberPackets was not being updated if less was taken than given.
// THIS ASSUMES CBR!
UInt32 bytesPerPacketOfInput = mInputFormat.mBytesPerPacket;
UInt32 theAvailablePacketSize = theAvailableByteSize / bytesPerPacketOfInput;
UInt32 minPacketSize = ioNumberPackets < theAvailablePacketSize ? ioNumberPackets : theAvailablePacketSize;
UInt32 minByteSize = minPacketSize * bytesPerPacketOfInput;
// we can copy only as much data as there is or up to how much space is availiable
ioNumberPackets = minPacketSize;
// <<jamesmcc
// now we have to copy the data taking into account the wrap around and where the start is
if(mInputBufferEnd + minByteSize < mInputBufferByteSize)
{
// no wrap around here
memset(mInputBuffer + mInputBufferEnd, 0, minByteSize);
// adjust the end point
mInputBufferEnd += minByteSize;
}
else
{
// the copy will wrap
// copy the first part
UInt32 theBeforeWrapByteSize = mInputBufferByteSize - mInputBufferEnd;
memset(mInputBuffer + mInputBufferEnd, 0, theBeforeWrapByteSize);
// and the rest
UInt32 theAfterWrapByteSize = minByteSize - theBeforeWrapByteSize;
memset(mInputBuffer, 0, theAfterWrapByteSize);
// adjust the end point
mInputBufferEnd = theAfterWrapByteSize;
}
}
void ACSimpleCodec::ConsumeInputData(UInt32 inConsumedByteSize)
{
// this is a convenience routine to make maintaining the ring buffer state easy
UInt32 theContiguousRange = GetInputBufferContiguousByteSize();
if(inConsumedByteSize > GetUsedInputBufferByteSize()) CODEC_THROW(kAudioCodecUnspecifiedError);
if(inConsumedByteSize <= theContiguousRange)
{
// the region to consume doesn't wrap
// figure out how much to consume
inConsumedByteSize = (theContiguousRange < inConsumedByteSize) ? theContiguousRange : inConsumedByteSize;
// clear the consumed bits
memset(mInputBuffer + mInputBufferStart, 0, inConsumedByteSize);
// adjust the start
mInputBufferStart += inConsumedByteSize;
}
else
{
// the region to consume will wrap
// clear the bits to the end of the buffer
memset(mInputBuffer + mInputBufferStart, 0, theContiguousRange);
// now clear the bits left from the start
memset(mInputBuffer, 0, inConsumedByteSize - theContiguousRange);
// adjust the start
mInputBufferStart = inConsumedByteSize - theContiguousRange;
}
}
Byte* ACSimpleCodec::GetBytes(UInt32& ioNumberBytes) const
{
// if a client's algorithm has to have contiguous data and mInputBuffer wraps, then someone has to make a copy.
// I can do it more efficiently than the client.
if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
//UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
if (ioNumberBytes > theUsedByteSize) ioNumberBytes = theUsedByteSize;
SInt32 leftOver = mInputBufferStart + ioNumberBytes - mInputBufferByteSize;
if(leftOver > 0)
{
// need to copy beginning of buffer to the end.
// We cleverly over allocated our buffer space to make this possible.
memmove(mInputBuffer + mInputBufferByteSize, mInputBuffer, leftOver);
}
return GetInputBufferStart();
}
void ACSimpleCodec::ReallocateInputBuffer(UInt32 inInputBufferByteSize)
{
mInputBufferByteSize = inInputBufferByteSize + kBufferPad;
// toss the old buffer
delete[] mInputBuffer;
mInputBuffer = NULL;
// allocate the new one
// allocate extra in order to allow making contiguous data.
UInt32 allocSize = 2*inInputBufferByteSize + kBufferPad;
mInputBuffer = new Byte[allocSize];
memset(mInputBuffer, 0, allocSize);
// reset the ring buffer state
mInputBufferStart = 0;
mInputBufferEnd = 0;
}
void ACSimpleCodec::GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outPropertyDataSize, Boolean& outWritable)
{
switch(inPropertyID)
{
case kAudioCodecPropertyInputBufferSize:
outPropertyDataSize = SizeOf32(UInt32);
outWritable = true;
break;
default:
ACBaseCodec::GetPropertyInfo(inPropertyID, outPropertyDataSize, outWritable);
break;
}
}
void ACSimpleCodec::SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData)
{
switch(inPropertyID)
{
case kAudioCodecPropertyInputBufferSize:
if(inPropertyDataSize == sizeof(UInt32))
{
ReallocateInputBuffer(*reinterpret_cast<const UInt32*>(inPropertyData));
}
else
{
CODEC_THROW(kAudioCodecBadPropertySizeError);
}
break;
default:
ACBaseCodec::SetProperty(inPropertyID, inPropertyDataSize, inPropertyData);
break;
}
}

View File

@@ -0,0 +1,105 @@
/*
File: ACSimpleCodec.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__ACSimpleCodec_h__)
#define __ACSimpleCodec_h__
//=============================================================================
// Includes
//=============================================================================
#include "ACBaseCodec.h"
//=============================================================================
// ACSimpleCodec
//
// This extension of ACBaseCodec provides for a simple ring buffer to handle
// input data.
//=============================================================================
class ACSimpleCodec
:
public ACBaseCodec
{
// Construction/Destruction
public:
ACSimpleCodec(UInt32 inInputBufferByteSize, AudioComponentInstance inInstance);
virtual ~ACSimpleCodec();
// Data Handling
public:
virtual void Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize) = 0;
virtual void Uninitialize();
virtual void Reset();
virtual void AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription);
virtual void ZeroPadInputData(UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription);
virtual UInt32 GetInputBufferByteSize() const;
virtual UInt32 GetUsedInputBufferByteSize() const;
virtual void GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outPropertyDataSize, Boolean& outWritable);
virtual void SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData);
protected:
void ConsumeInputData(UInt32 inConsumedByteSize);
Byte* GetInputBufferStart() const { return mInputBuffer + mInputBufferStart; }
UInt32 GetInputBufferContiguousByteSize() const { return (mInputBufferStart <= mInputBufferEnd) ? (mInputBufferEnd - mInputBufferStart) : (mInputBufferByteSize - mInputBufferStart); }
virtual void ReallocateInputBuffer(UInt32 inInputBufferByteSize);
// returns a pointer to contiguous bytes.
// will do some copying if the request wraps around the internal buffer.
// request must be less than available bytes
Byte* GetBytes(UInt32& ioNumberBytes) const;
private:
Byte* mInputBuffer;
UInt32 mInputBufferByteSize;
UInt32 mInputBufferStart;
UInt32 mInputBufferEnd;
};
#endif

View File

@@ -0,0 +1,76 @@
/*
File: GetCodecBundle.cpp
Abstract: GetCodecBundle.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "GetCodecBundle.h"
#if TARGET_OS_WIN32
#include "CAWin32StringResources.h"
#endif
#if TARGET_OS_WIN32
#define kCodecBundleID "com.apple.audio.codecs.Components"
#else
const CFStringRef kCodecBundleID = CFSTR("com.apple.audio.codecs.Components");
#endif
CFBundleRef GetCodecBundle()
{
static CFBundleRef sAudioCodecBundle = 0;
if (!sAudioCodecBundle)
{
#if TARGET_OS_WIN32
sAudioCodecBundle = CFBundleGetBundleWithIdentifier(CFSTR(kCodecBundleID));
#else
sAudioCodecBundle = CFBundleGetBundleWithIdentifier(kCodecBundleID);
#endif
if (sAudioCodecBundle)
{
CFRetain(sAudioCodecBundle);
}
}
return sAudioCodecBundle;
}

View File

@@ -0,0 +1,60 @@
/*
File: GetCodecBundle.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef _GetCodecBundle_
#define _GetCodecBundle_
#include <TargetConditionals.h>
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreFoundation/CFBundle.h>
#else
#include "CFBundle.h"
#endif
CFBundleRef GetCodecBundle();
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,311 @@
/*
File: AudioFileComponentBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AudioFileComponentBase_h__
#define __AudioFileComponentBase_h__
#include "ComponentBase.h"
#include "AudioFileFormat.h"
struct AudioFileComponentLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AudioFileComponentFactory : public APFactory<AudioFileComponentLookup, Implementor>
{
};
/* subclass, override AudioFileComponentBase() and GetAudioFormat() and that's it. */
class AudioFileComponentBase : public ComponentBase
{
public:
AudioFileComponentBase(AudioComponentInstance inInstance);
virtual ~AudioFileComponentBase();
virtual AudioFileFormatBase* GetAudioFileFormatBase() const = 0;
/* Public API Function Support */
virtual OSStatus AFAPI_CreateURL(
CFURLRef inFileRef,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags) { return kAudio_UnimplementedError; }
virtual OSStatus AFAPI_OpenURL(
CFURLRef inFileRef,
SInt8 inPermissions,
int inFD) { return kAudio_UnimplementedError; }
virtual OSStatus AFAPI_Create(
const FSRef *inParentRef,
CFStringRef inFileName,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags,
FSRef *outNewFileRef) { return kAudio_UnimplementedError; }
virtual OSStatus AFAPI_Initialize(
const FSRef *inFileRef,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags) { return kAudio_UnimplementedError; }
virtual OSStatus AFAPI_Open(
const FSRef *inFileRef,
SInt8 inPermissions,
SInt16 inRefNum) { return kAudio_UnimplementedError; }
virtual OSStatus AFAPI_OpenWithCallbacks(
void * inRefCon,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc)=0;
virtual OSStatus AFAPI_InitializeWithCallbacks(
void * inRefCon,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc,
UInt32 inFileType,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags)=0;
virtual OSStatus AFAPI_Close()=0;
virtual OSStatus AFAPI_Optimize()=0;
virtual OSStatus AFAPI_ReadBytes( Boolean inUseCache,
SInt64 inStartingByte,
UInt32 *ioNumBytes,
void *outBuffer)=0;
virtual OSStatus AFAPI_WriteBytes( Boolean inUseCache,
SInt64 inStartingByte,
UInt32 *ioNumBytes,
const void *inBuffer)=0;
virtual OSStatus AFAPI_ReadPackets( Boolean inUseCache,
UInt32 *outNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer)=0;
virtual OSStatus AFAPI_ReadPacketData( Boolean inUseCache,
UInt32 *ioNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer)=0;
virtual OSStatus AFAPI_WritePackets( Boolean inUseCache,
UInt32 inNumBytes,
const AudioStreamPacketDescription *inPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
const void *inBuffer)=0;
virtual OSStatus AFAPI_GetPropertyInfo( AudioFilePropertyID inPropertyID,
UInt32 *outDataSize,
UInt32 *isWritable)=0;
virtual OSStatus AFAPI_GetProperty( AudioFilePropertyID inPropertyID,
UInt32 *ioDataSize,
void *ioPropertyData)=0;
virtual OSStatus AFAPI_SetProperty( AudioFilePropertyID inPropertyID,
UInt32 inDataSize,
const void *inPropertyData)=0;
virtual OSStatus AFAPI_GetGlobalInfoSize(
AudioFilePropertyID inPropertyID,
UInt32 inSpecifierSize,
const void* inSpecifier,
UInt32 *outPropertySize);
virtual OSStatus AFAPI_GetGlobalInfo(
AudioFilePropertyID inPropertyID,
UInt32 inSpecifierSize,
const void* inSpecifier,
UInt32 *ioPropertySize,
void *ioPropertyData);
virtual OSStatus AFAPI_CountUserData( UInt32 inUserDataID,
UInt32 *outNumberItems)=0;
virtual OSStatus AFAPI_GetUserDataSize( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 *outDataSize)=0;
virtual OSStatus AFAPI_GetUserData( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 *ioDataSize,
void *ioUserData)=0;
virtual OSStatus AFAPI_SetUserData( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 inDataSize,
const void *inUserData)=0;
virtual OSStatus AFAPI_RemoveUserData( UInt32 inUserDataID,
UInt32 inIndex)=0;
#if !CA_USE_AUDIO_PLUGIN_ONLY
static OSStatus ComponentEntryDispatch(ComponentParameters *p, AudioFileComponentBase *This);
#endif
protected:
};
class AudioFileObjectComponentBase : public AudioFileComponentBase
{
public:
AudioFileObjectComponentBase(AudioComponentInstance inInstance);
virtual ~AudioFileObjectComponentBase();
virtual AudioFileFormat* GetAudioFormat() const = 0;
virtual AudioFileFormatBase* GetAudioFileFormatBase() const { return GetAudioFormat(); }
void SetAudioFileObject(AudioFileObject* inObject) { mAudioFileObject = inObject; }
/* Public API Function Support */
virtual OSStatus AFAPI_CreateURL(
CFURLRef inFileRef,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags);
virtual OSStatus AFAPI_OpenURL(
CFURLRef inFileRef,
SInt8 inPermissions,
int inFD);
virtual OSStatus AFAPI_OpenWithCallbacks(
void * inRefCon,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc);
virtual OSStatus AFAPI_InitializeWithCallbacks(
void * inRefCon,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc,
UInt32 inFileType,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags);
virtual OSStatus AFAPI_Close();
virtual OSStatus AFAPI_Optimize();
virtual OSStatus AFAPI_ReadBytes( Boolean inUseCache,
SInt64 inStartingByte,
UInt32 *ioNumBytes,
void *outBuffer);
virtual OSStatus AFAPI_WriteBytes( Boolean inUseCache,
SInt64 inStartingByte,
UInt32 *ioNumBytes,
const void *inBuffer);
virtual OSStatus AFAPI_ReadPackets( Boolean inUseCache,
UInt32 *outNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer);
virtual OSStatus AFAPI_ReadPacketData( Boolean inUseCache,
UInt32 *ioNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer);
virtual OSStatus AFAPI_WritePackets( Boolean inUseCache,
UInt32 inNumBytes,
const AudioStreamPacketDescription *inPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
const void *inBuffer);
virtual OSStatus AFAPI_GetPropertyInfo( AudioFilePropertyID inPropertyID,
UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus AFAPI_GetProperty( AudioFilePropertyID inPropertyID,
UInt32 *ioDataSize,
void *ioPropertyData);
virtual OSStatus AFAPI_SetProperty( AudioFilePropertyID inPropertyID,
UInt32 inDataSize,
const void *inPropertyData);
virtual OSStatus AFAPI_CountUserData( UInt32 inUserDataID,
UInt32 *outNumberItems);
virtual OSStatus AFAPI_GetUserDataSize( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 *outDataSize);
virtual OSStatus AFAPI_GetUserData( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 *ioDataSize,
void *ioUserData);
virtual OSStatus AFAPI_SetUserData( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 inDataSize,
const void *inUserData);
virtual OSStatus AFAPI_RemoveUserData( UInt32 inUserDataID,
UInt32 inIndex);
protected:
AudioFileObject* mAudioFileObject;
};
#endif

View File

@@ -0,0 +1,71 @@
/*
File: AudioFileFormat.cpp
Abstract: AudioFileFormat.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AudioFileFormat.h"
#include "DataSource.h"
AudioFileFormatBase::AudioFileFormatBase(UInt32 inFileType)
: mFileType(inFileType)
{
}
AudioFileFormatBase::~AudioFileFormatBase()
{
}
OSStatus AudioFileFormatBase::GetHFSCodes(UInt32* ioDataSize, void* outPropertyData)
{
return kAudioFileUnsupportedPropertyError;
}
AudioFileFormat::AudioFileFormat(UInt32 inFileType)
: AudioFileFormatBase(inFileType)
{
}
AudioFileFormat::~AudioFileFormat()
{
}

View File

@@ -0,0 +1,125 @@
/*
File: AudioFileFormat.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef _AudioFileFormat_H_
#define _AudioFileFormat_H_
#include "AudioFileObject.h"
// AudioFileFormat is a factory class for AudioFileObjects.
// UncertainResult is needed for DataIsThisFormat.
// In the case of SoundDesigner 2 we can't determine if the data is SoundDesigner 2 or not.
typedef int UncertainResult;
enum {
kFalse = 0,
kTrue = 1,
kCantDetermine = -1
};
class AudioFileHandle;
class AudioFileFormat;
class AudioFileFormatComponent;
class AudioFileFormatBase
{
public:
AudioFileFormatBase(UInt32 inFileType);
virtual ~AudioFileFormatBase();
// return true if extension is of this format type
virtual Boolean ExtensionIsThisFormat(CFStringRef inExtension) = 0;
virtual UncertainResult FileDataIsThisFormat(
UInt32 /*inDataByteSize*/,
const void* /*inData*/) = 0;
// support SoundDesigner II files while minimizing opening and closing files.
virtual Boolean ResourceIsThisFormat(const FSRef* /*inRef*/) { return false; }
UInt32 GetFileType() const { return mFileType; }
virtual UInt32 CanRead() const { return 1; }
virtual UInt32 CanWrite() const { return 1; }
virtual UInt32 HasResourceFork() const { return 0; }
virtual void GetExtensions(CFArrayRef *outArray) = 0;
virtual void GetUTIs(CFArrayRef *outArray) {}
virtual void GetMIMETypes(CFArrayRef *outArray) {}
virtual void GetFileTypeName(CFStringRef *outName) = 0;
virtual OSStatus GetAvailableFormatIDs(UInt32* ioDataSize, void* outPropertyData) = 0;
virtual OSStatus GetAvailableStreamDescriptions(UInt32 inFormatID, UInt32* ioDataSize, void* outPropertyData) = 0;
virtual OSStatus GetHFSCodes(UInt32* ioDataSize, void* outPropertyData);
virtual AudioFileFormat* AsAudioFileFormat() { return NULL; }
virtual AudioFileFormatComponent* AsAudioFileFormatComponent() { return NULL; }
private:
UInt32 mFileType;
};
class AudioFileStreamObject;
class AudioFileFormat : public AudioFileFormatBase
{
public:
AudioFileFormat(UInt32 inFileType);
virtual ~AudioFileFormat();
// create an AudioFileObject for this format type.
virtual AudioFileObject* New() = 0;
virtual AudioFileStreamObject* NewStream() { return NULL; }
// return true if file is of this format type
virtual UncertainResult FileDataIsThisFormat(UInt32 inDataByteSize, const void* inData) = 0;
virtual AudioFileFormat* AsAudioFileFormat() { return this; }
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,667 @@
/*
File: AudioFileObject.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef _AudioFileObject_H_
#define _AudioFileObject_H_
#include <TargetConditionals.h>
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreAudio/CoreAudioTypes.h>
#include <AudioToolbox/AudioFile.h>
#include <AudioToolbox/AudioFormat.h>
#else
#include "CoreAudioTypes.h"
#include "AudioFile.h"
#include "AudioFormat.h"
#endif
#include "CompressedPacketTable.h"
#include "CACFDictionary.h"
#include "DataSource.h"
#include <vector>
#include <fcntl.h>
#if TARGET_OS_WIN32
#include <io.h>
#endif
/*
These are structs defined in 10.5. They are included here for compatibility with sources
*/
#if COREAUDIOTYPES_VERSION < 1050
struct AudioFormatListItem
{
AudioStreamBasicDescription mASBD;
AudioChannelLayoutTag mChannelLayoutTag;
};
typedef struct AudioFormatListItem AudioFormatListItem;
struct AudioFormatInfo
{
AudioStreamBasicDescription mASBD;
const void* mMagicCookie;
UInt32 mMagicCookieSize;
};
typedef struct AudioFormatInfo AudioFormatInfo;
enum {
kAudioFormatProperty_FormatList = 'flst',
// Returns a list of AudioFormatListItem structs describing the audio formats contained within the compressed bit stream
// as described by the magic cookie.
// The specifier is an AudioFormatInfo struct. At a minimum formatID member of the ASBD struct must filled in. Other fields
// may be filled in.
kAudioFormatProperty_OutputFormatList = 'ofls',
// Returns a list of AudioFormatListItem structs describing the audio formats which may be obtained by decoding the format
// described by the specifier.
// The specifier is an AudioFormatInfo struct. At a minimum formatID member of the ASBD struct must filled in. Other fields
// may be filled in. If there is no magic cookie, then the number of channels and sample rate should be filled in.
};
enum {
kAudioFilePropertyPacketSizeUpperBound = 'pkub',
kAudioFilePropertyFormatList = 'flst',
kAudioFilePropertyEstimatedDuration = 'edur',
kAudioFilePropertyBitRate = 'brat'
};
enum {
kAudioFileCreateURLSelect = 0x0019,
kAudioFileOpenURLSelect = 0x001A,
kAudioFileFileDataIsThisFormatSelect = 0x001B
};
#endif
enum {
kTEMPAudioFilePropertySoundCheckDictionary = 'scdc',
kTEMPAudioFilePropertyLoudnessInfo = 'loud',
kTEMPAudioFilePropertyGenerateLoudnessInfo = 'glou'
};
const UInt32 kCopySoundDataBufferSize = 1024 * 1024;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// some files encode these as upper case
enum {
kUpperCase_IMACompression = 'IMA4', /*IMA 4:1*/
kUpperCase_ULawCompression = 'ULAW', /*<2A>Law 2:1*/
kUpperCase_ALawCompression = 'ALAW', /*aLaw 2:1*/
kUpperCase_Float32 = 'FL32',
kUpperCase_Float64 = 'FL64'
};
enum
{
// in what header is this defined? what is it?
kGSM = 'agsm',
kUpperCase_GSM = 'GSM '
};
#define kPackedBESInt (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked)
#define kPackedLESInt (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked)
#define kPackedBEFloat (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked)
#define kPackedLEFloat (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline int TransformPerm_FS_O (SInt8 inPerm)
{
switch (inPerm) {
case kAudioFileReadPermission: return O_RDONLY;
case kAudioFileWritePermission: return O_WRONLY;
case kAudioFileReadWritePermission: return O_RDWR;
}
return O_RDONLY;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark "File Error Handling"
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <errno.h>
#include <CoreAudio/CoreAudioTypes.h>
inline OSErr AudioFileTranslateErrno(int err)
{
switch (err) {
#if !TARGET_OS_WIN32
case ENFILE:
#endif
case EMFILE:
return -42 /* kAudio_TooManyFilesOpenError */;
#if !TARGET_OS_WIN32
case EPERM:
case EROFS:
#endif
case EACCES:
case EEXIST:
return -54 /* kAudio_FilePermissionError */;
#if !TARGET_OS_WIN32
case EMLINK:
return (OSErr)'!pth' /* kAudio_BadFilePathError */;
case ENOTDIR:
case ELOOP:
#endif
case ENOENT:
default:
return (OSErr)kAudioFileUnspecifiedError;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioFileObject
{
protected:
private:
SInt64 mNumBytes; // total bytes of audio data in the audio file
SInt64 mNumPackets; // total frames of audio data in the audio file
AudioStreamBasicDescription mDataFormat; // format of the audio data
SInt64 mDataOffset; // position if the file where audio data begins
UInt32 mIsOptimized; // 1 if there is nothing in the file following the audio data, 0 if there is
UInt32 mFileType; // file type of the audio file (i.e. AIFF, WAVE, etc.)
CFURLRef mFileRef; // URL of the file passed to AudioFileOpen or AudioFileCreate
int mFileD; // Ref num of the file after opening within Audio File
SInt8 mPermissions; // file permissions indicated by the caller, passed by AudioFileOpen or set with SetProperty function
Boolean mIsInitialized; // has the AudioFileObject for this file been intialized?
DataSource *mDataSource;
UInt32 mMaximumPacketSize;
CompressedPacketTable *mPacketTable;
UInt32 mDeferSizeUpdates;
Boolean mNeedsSizeUpdate;
Boolean mFirstSetFormat;
Boolean mAlignDataWithFillerChunks;
public:
AudioFileObject (UInt32 inFileType)
: mNumBytes(0),
mNumPackets(0),
mDataOffset(0),
mIsOptimized(1),
mFileType(inFileType),
mFileRef(NULL),
mFileD(-1),
mPermissions(0),
mIsInitialized (false),
mDataSource(0),
mMaximumPacketSize(0),
mPacketTable(NULL),
mDeferSizeUpdates(1),
mNeedsSizeUpdate(false),
mFirstSetFormat(true),
mAlignDataWithFillerChunks(true)
{
memset(&mDataFormat, 0, sizeof(mDataFormat));
}
virtual ~AudioFileObject();
/* Public API Function Implementation */
// The DoSomething() versions of these functions are wrappers that perform a standard prologue.
// The Something() methods are those which should be overridden in the subclasses.
OSStatus DoCreate( CFURLRef inFileRef,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags);
virtual OSStatus Create( CFURLRef inFileRef,
const AudioStreamBasicDescription *inFormat);
OSStatus DoOpen( CFURLRef inFileRef,
SInt8 inPermissions,
int inFD);
virtual OSStatus Open( CFURLRef inFileRef,
SInt8 inPermissions,
int inFD);
OSStatus DoOpenWithCallbacks(
void * inRefCon,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc);
OSStatus DoInitialize( CFURLRef inFileRef,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags);
virtual OSStatus Initialize( CFURLRef inFileRef,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags);
OSStatus DoInitializeWithCallbacks(
void * inRefCon,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc,
UInt32 inFileType,
const AudioStreamBasicDescription *inFormat,
UInt32 inFlags);
virtual OSStatus OpenFromDataSource(void);
virtual OSStatus InitializeDataSource(const AudioStreamBasicDescription *inFormat, UInt32 inFlags);
OSStatus DoClose();
virtual OSStatus Close();
OSStatus DoOptimize();
virtual OSStatus Optimize();
virtual OSStatus ReadBytes( Boolean inUseCache,
SInt64 inStartingByte,
UInt32 *ioNumBytes,
void *outBuffer);
virtual OSStatus WriteBytes( Boolean inUseCache,
SInt64 inStartingByte,
UInt32 *ioNumBytes,
const void *inBuffer);
virtual OSStatus ReadPackets( Boolean inUseCache,
UInt32 *outNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer);
virtual OSStatus ReadPacketData(
Boolean inUseCache,
UInt32 *ioNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer);
virtual OSStatus ReadPacketDataVBR(
Boolean inUseCache,
UInt32 *ioNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer);
virtual OSStatus HowManyPacketsCanBeReadIntoBuffer(UInt32* ioNumBytes, SInt64 inStartingPacket, UInt32 *ioNumPackets);
virtual OSStatus ReadPacketDataVBR_InTable(
Boolean inUseCache,
UInt32 *ioNumBytes,
AudioStreamPacketDescription *outPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
void *outBuffer);
virtual OSStatus WritePackets( Boolean inUseCache,
UInt32 inNumBytes,
const AudioStreamPacketDescription *inPacketDescriptions,
SInt64 inStartingPacket,
UInt32 *ioNumPackets,
const void *inBuffer);
/* Property Support */
virtual OSStatus GetPropertyInfo (
AudioFilePropertyID inPropertyID,
UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus GetProperty ( AudioFilePropertyID inPropertyID,
UInt32 *ioDataSize,
void *ioPropertyData);
virtual OSStatus SetProperty ( AudioFilePropertyID inPropertyID,
UInt32 inDataSize,
const void *inPropertyData);
UInt32 GetFileType() const { return mFileType; }
void SetFileType(UInt32 inFileType) { mFileType = inFileType; }
// this will set the format in memory only.
virtual OSStatus SetDataFormat(const AudioStreamBasicDescription* inStreamFormat);
// this will update the format info on disk and in memory.
virtual OSStatus UpdateDataFormat(const AudioStreamBasicDescription* inStreamFormat);
const UInt32 GetBytesPerPacket() const { return mDataFormat.mBytesPerPacket; }
const AudioStreamBasicDescription &GetDataFormat() const { return mDataFormat; }
virtual OSStatus GetFormatListInfo( UInt32 &outDataSize,
UInt32 &outWritable);
virtual OSStatus GetFormatList( UInt32 &ioDataSize,
AudioFormatListItem *ioPropertyData);
virtual OSStatus SetFormatList( UInt32 inDataSize,
const AudioFormatListItem *inPropertyData);
virtual OSStatus UpdateSize() { return noErr; }
UInt32 DeferSizeUpdates() { return mDeferSizeUpdates; }
void SetDeferSizeUpdates(UInt32 inFlag) { mDeferSizeUpdates = inFlag; }
OSStatus UpdateSizeIfNeeded();
OSStatus SizeChanged();
Boolean IsOptimized() const { return mIsOptimized != 0; }
void SetIsOptimized(Boolean inIsOptimized) { mIsOptimized = inIsOptimized ? 1 : 0; }
Boolean AlignDataWithFillerChunks() const { return mAlignDataWithFillerChunks; }
virtual SInt64 GetNumBytes() { return mNumBytes; }
virtual void SetNumBytes(SInt64 inNumBytes) { mNumBytes = inNumBytes; }
// this will update the header size info on disk
OSStatus UpdateNumBytes(SInt64 inNumBytes);
virtual SInt64 GetNumPackets(){ return mNumPackets; }
virtual void SetNumPackets(SInt64 inNumPackets) { mNumPackets = inNumPackets; }
// this will update the header size info on disk
OSStatus UpdateNumPackets(SInt64 inNumPackets);
virtual OSStatus PacketToFrame(SInt64 inPacket, SInt64& outFirstFrameInPacket);
virtual OSStatus FrameToPacket(SInt64 inFrame, SInt64& outPacket, UInt32& outFrameOffsetInPacket);
virtual OSStatus PacketToByte(AudioBytePacketTranslation* abpt);
virtual OSStatus ByteToPacket(AudioBytePacketTranslation* abpt);
virtual OSStatus GetBitRate( UInt32 *outBitRate);
virtual OSStatus GetMagicCookieDataSize( UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus GetMagicCookieData( UInt32 *ioDataSize,
void *ioPropertyData);
virtual OSStatus SetMagicCookieData( UInt32 inDataSize,
const void *inPropertyData);
virtual OSStatus GetMarkerListSize( UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus GetMarkerList( UInt32 *ioDataSize,
AudioFileMarkerList *ioMarkerList);
virtual OSStatus SetMarkerList( UInt32 inDataSize,
const AudioFileMarkerList *inMarkerList);
virtual OSStatus GetRegionListSize( UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus GetRegionList( UInt32 *ioDataSize,
AudioFileRegionList *ioRegionList);
virtual OSStatus SetRegionList( UInt32 inDataSize,
const AudioFileRegionList *inRegionList);
virtual OSStatus GetChannelLayoutSize( UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus GetChannelLayout( UInt32 *ioDataSize,
AudioChannelLayout *ioChannelLayout);
virtual OSStatus SetChannelLayout( UInt32 inDataSize,
const AudioChannelLayout *inChannelLayout);
virtual OSStatus GetInfoDictionarySize( UInt32 *outDataSize,
UInt32 *isWritable);
virtual OSStatus GetInfoDictionary( CACFDictionary *infoDict);
virtual OSStatus SetInfoDictionary( CACFDictionary *infoDict);
virtual OSStatus GetSoundCheckDictionarySize( UInt32 *outDataSize,
UInt32 *isWritable) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetSoundCheckDictionary( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus SetSoundCheckDictionary( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetLoudnessInfo( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetSoundCheckDictionaryFromLoudnessInfo(CACFDictionary* outInfoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetLoudnessInfoFromSoundCheckDictionary(CACFDictionary* outInfoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus SetLoudnessInfo( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetLoudnessInfoSize( UInt32 *outDataSize,
UInt32 *isWritable) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GenerateLoudnessInfo( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetEstimatedDuration( Float64* duration);
virtual OSStatus CountUserData( UInt32 inUserDataID,
UInt32 *outNumberItems);
virtual OSStatus GetUserDataSize( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 *outDataSize);
virtual OSStatus GetUserData( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 *ioDataSize,
void *ioUserData);
virtual OSStatus SetUserData( UInt32 inUserDataID,
UInt32 inIndex,
UInt32 inDataSize,
const void *inUserData);
virtual OSStatus RemoveUserData( UInt32 inUserDataID,
UInt32 inIndex);
virtual OSStatus GetLyrics(CFStringRef *outLyrics) { return kAudioFileUnsupportedPropertyError; }
Boolean CanRead() const { return mPermissions & kAudioFileReadPermission; }
Boolean CanWrite() const { return mPermissions & kAudioFileWritePermission; }
void SetPermissions(SInt8 inPermissions) { mPermissions = inPermissions; }
/* Other Helper Methods: (some may not be necessary depending on how things are refactored) */
OSStatus OpenFile(SInt8 inPermissions, int inFD);
OSStatus CreateDataFile (CFURLRef inFileRef, int &outFileD);
OSStatus AddDurationToInfoDictionary(CACFDictionary *infoDict, Float64 &inDuration);
virtual Boolean IsDataFormatSupported(const AudioStreamBasicDescription *inFormat) = 0;
virtual Boolean IsDataFormatValid(const AudioStreamBasicDescription *inFormat);
virtual OSStatus IsValidFilePosition(SInt64 /*position*/) { return noErr; }
OSStatus MoveData(SInt64 fromPos, SInt64 toPos, SInt64 size);
/* Accessors: */
Boolean IsInitialized() const { return mIsInitialized; }
void SetInitialized(Boolean inFlag) { mIsInitialized = inFlag; }
DataSource* GetDataSource() const { return mDataSource; }
void SetDataSource(DataSource *inDataSource);
void SetURL (CFURLRef inURL);
virtual UInt32 GetMaximumPacketSize() { return mMaximumPacketSize; }
virtual UInt32 FindMaximumPacketSize() { return mMaximumPacketSize; }
virtual void SetMaximumPacketSize(const UInt32 inPacketSize) { mMaximumPacketSize = inPacketSize; }
virtual UInt32 GetPacketSizeUpperBound() { return GetMaximumPacketSize (); }
SInt64 GetDataOffset() const { return mDataOffset; }
void SetDataOffset(SInt64 inOffset) { mDataOffset = inOffset; }
// I like this idiom better than DoesPacketTableExist+NewPacketTable:
CompressedPacketTable* GetPacketTable(Boolean inCreateIt = false)
{
if (!mPacketTable && inCreateIt)
mPacketTable = new CompressedPacketTable(mDataFormat.mFramesPerPacket);
return mPacketTable;
}
void ClearPacketTable()
{
DeletePacketTable();
GetPacketTable(true);
}
virtual OSStatus ScanForPackets(SInt64 inToPacketCount, DataSource* inDataSrc = NULL, bool fullyParsedIfEndOfDataReached = true)
{
// In formats that read packets lazily, this will be overridden to scan for packets up to the index.
if (inToPacketCount > GetNumPackets())
return kAudioFileEndOfFileError;
return noErr;
}
void AppendPacket(const AudioStreamPacketDescription &inPacket)
{
CompressedPacketTable* packetTable = GetPacketTable(true);
UInt32 numFramesInPacket = mDataFormat.mFramesPerPacket ? mDataFormat.mFramesPerPacket : inPacket.mVariableFramesInPacket;
AudioStreamPacketDescriptionExtended pext;
memset(&pext, 0, sizeof(pext));
pext.mStartOffset = inPacket.mStartOffset;
pext.mDataByteSize = inPacket.mDataByteSize;
pext.mVariableFramesInPacket = inPacket.mVariableFramesInPacket;
pext.mFrameOffset = numFramesInPacket + (packetTable->size() ? packetTable->back().mFrameOffset : 0);
packetTable->push_back(pext);
if (inPacket.mDataByteSize > mMaximumPacketSize)
mMaximumPacketSize = inPacket.mDataByteSize;
}
void DeletePacketTable() { delete mPacketTable; mPacketTable = NULL;}
SInt64 GetPacketTableSize() { return mPacketTable ? mPacketTable->size() : 0; }
OSStatus GetPacketDescriptions(UInt32 inStartingPacket, UInt32 *ioDataSize, AudioStreamPacketDescription *outPacketDescriptions)
{
if (outPacketDescriptions == NULL) return kAudioFileUnspecifiedError;
if (mPacketTable)
{
// only get as many packet descriptions as can fit in outPacketDescriptions
UInt32 count = *ioDataSize / sizeof(AudioStreamPacketDescription);
if (count + inStartingPacket > GetPacketTableSize())
count = (UInt32)(GetPacketTableSize() - inStartingPacket);
*ioDataSize = 0;
for (UInt32 i = inStartingPacket; i < (count + inStartingPacket); i++)
{
AudioStreamPacketDescription curPacket = (*mPacketTable)[i];
outPacketDescriptions[i].mStartOffset = curPacket.mStartOffset - GetDataOffset();
outPacketDescriptions[i].mVariableFramesInPacket = curPacket.mVariableFramesInPacket;
outPacketDescriptions[i].mDataByteSize = curPacket.mDataByteSize;
*ioDataSize += sizeof(AudioStreamPacketDescription);
}
}
else
*ioDataSize = 0;
return noErr;
}
#if DEBUG
void DumpPacketTable()
{
if (mPacketTable) {
SInt64 size = mPacketTable->size();
printf("PacketTable size %d\n", (int)size);
for (SInt64 i = 0; i < size; i++) {
AudioStreamPacketDescription curPacket = (*mPacketTable)[i];
printf("dpkt %5qd %8qd %5d %5d\n", i, curPacket.mStartOffset, (int)curPacket.mDataByteSize, (int)curPacket.mVariableFramesInPacket);
}
}
}
#endif
Boolean GetNeedsSizeUpdate() const { return mNeedsSizeUpdate; }
void SetNeedsSizeUpdate(Boolean inNeedsSizeUpdate) { mNeedsSizeUpdate = inNeedsSizeUpdate; }
CFURLRef GetURL () const { return mFileRef; }
virtual OSStatus GetSourceBitDepth(SInt32& outValue) { outValue = 0; return kAudioFileUnsupportedPropertyError; }
virtual OSStatus SetSourceBitDepth(SInt32 inValue) { return kAudioFileUnsupportedPropertyError; }
virtual OSStatus GetAlbumArtwork(CFDataRef& outValue) { outValue = NULL; return kAudioFileUnsupportedPropertyError; }
virtual OSStatus SetAlbumArtwork(CFDataRef inValue){ return kAudioFileUnsupportedPropertyError; }
private:
void SetAlignDataWithFillerChunks(Boolean inFlag) { mAlignDataWithFillerChunks = inFlag; }
OSStatus ValidateFormatAndData();
/* debug */
// virtual void PrintFile (FILE* inFile, const char *indent) = 0;
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline Boolean cfstrcmpi(CFStringRef a, CFStringRef b)
{
// case insensitive CFString compare
return CFStringCompare(a, b, kCFCompareCaseInsensitive) == kCFCompareEqualTo;
}
CFBundleRef GetAudioToolboxBundle();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#endif

View File

@@ -0,0 +1,216 @@
/*
File: CompressedPacketTable.cpp
Abstract: CompressedPacketTable.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CompressedPacketTable.h"
#include "CAAutoDisposer.h"
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const UInt32 CompressedPacketTable::kShift = 5;
const UInt32 CompressedPacketTable::kMask = 31;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CompressedPacketTable::~CompressedPacketTable()
{
size_t size = mBases.size();
for (size_t i = 0; i < size; ++i) {
free(mBases[i].mDescs);
}
}
void CompressedPacketTable::push_back(const AudioStreamPacketDescriptionExtended& inDesc)
{
SInt64 baseIndex = mSize >> kShift;
UInt32 packetIndex = (UInt32)(mSize & kMask);
if (packetIndex == 0) {
// first packet in a new sequence. create a new PacketBase.
PacketBase newBase;
newBase.mBaseOffset = 0;
newBase.mDescs = CA_malloc((kMask+1) * sizeof(AudioStreamPacketDescriptionExtended));
newBase.mDescType = kExtendedPacketDescription;
mBases.push_back(newBase);
}
PacketBase& base = mBases[(size_t)baseIndex];
AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs;
descs[packetIndex] = inDesc;
if (packetIndex == kMask) {
// last packet in a sequence. compress the sequence.
Compress(base);
}
mSize++;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define ACCESS_TYPE(TYPE) \
case k##TYPE##ContiguousPacketDescription : { \
TYPE##ContiguousPacketDescription* descs = (TYPE##ContiguousPacketDescription*)base.mDescs; \
packetOffset = packetIndex ? descs[packetIndex-1].mNextOffset : 0; \
packetSize = (UInt32)(descs[packetIndex].mNextOffset - packetOffset); \
} break; \
case k##TYPE##DiscontiguousPacketDescription : { \
TYPE##DiscontiguousPacketDescription* descs = (TYPE##DiscontiguousPacketDescription*)base.mDescs; \
packetOffset = packetIndex ? descs[packetIndex-1].mNextOffset : 0; \
packetSize = descs[packetIndex].mDataByteSize; \
} break;
const AudioStreamPacketDescriptionExtended CompressedPacketTable::operator[](SInt64 inPacketIndex) const
{
SInt64 baseIndex = inPacketIndex >> kShift;
UInt32 packetIndex = (UInt32)(inPacketIndex & kMask);
if ((size_t)baseIndex >= mBases.size())
throw -1;
const PacketBase& base = mBases[(size_t)baseIndex];
SInt64 packetOffset = 0;
UInt32 packetSize = 0;
switch (base.mDescType)
{
ACCESS_TYPE(Tiny)
ACCESS_TYPE(Small)
ACCESS_TYPE(Big)
case kExtendedPacketDescription :
return ((AudioStreamPacketDescriptionExtended*)base.mDescs)[packetIndex];
}
AudioStreamPacketDescriptionExtended outDesc;
outDesc.mStartOffset = base.mBaseOffset + packetOffset;
outDesc.mDataByteSize = packetSize;
outDesc.mVariableFramesInPacket = 0;
outDesc.mFrameOffset = mFramesPerPacket * inPacketIndex;
//printf("get %d %10qd %10qd %2d %10qd %6d %10qd\n", base.mDescType, inPacketIndex, baseIndex, packetIndex, outDesc.mStartOffset, outDesc.mDataByteSize, outDesc.mFrameOffset);
return outDesc;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool CompressedPacketTable::isContiguous(PacketBase& base)
{
AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs;
SInt64 expectedOffset = descs[0].mStartOffset + descs[0].mDataByteSize;
for (UInt32 i = 1; i <= kMask; ++i) {
if (expectedOffset != descs[i].mStartOffset) return false;
expectedOffset += descs[i].mDataByteSize;
}
return true;
}
bool CompressedPacketTable::hasVariableFrames(PacketBase& base)
{
AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs;
for (UInt32 i = 0; i <= kMask; ++i) {
if (descs[i].mVariableFramesInPacket) return true;
}
return false;
}
UInt32 CompressedPacketTable::largestPacket(PacketBase& base)
{
UInt32 maxPacketSize = 0;
AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs;
for (UInt32 i = 0; i <= kMask; ++i) {
UInt32 packetSize = descs[i].mDataByteSize;
if (packetSize > maxPacketSize) maxPacketSize = packetSize;
}
return maxPacketSize;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define COMPRESS_TYPE(TYPE, BITS) \
if (contiguous) { \
TYPE##ContiguousPacketDescription* newDescs = (TYPE##ContiguousPacketDescription*)CA_malloc((kMask+1) * sizeof(TYPE##ContiguousPacketDescription)); \
base.mDescs = newDescs; \
base.mDescType = k##TYPE##ContiguousPacketDescription; \
for (UInt32 i = 0; i <= kMask; ++i) { \
newDescs[i].mNextOffset = (BITS)(descs[i].mStartOffset + descs[i].mDataByteSize - baseOffset); \
} \
free(descs); \
} else { \
TYPE##DiscontiguousPacketDescription* newDescs = (TYPE##DiscontiguousPacketDescription*)CA_malloc((kMask+1) * sizeof(TYPE##DiscontiguousPacketDescription)); \
base.mDescs = newDescs; \
base.mDescType = k##TYPE##DiscontiguousPacketDescription; \
for (UInt32 i = 0; i <= kMask; ++i) { \
newDescs[i].mNextOffset = i == kMask ? 0 : (BITS)(descs[i+1].mStartOffset - baseOffset); \
newDescs[i].mDataByteSize = descs[i].mDataByteSize; \
} \
free(descs); \
} \
return;
void CompressedPacketTable::Compress(PacketBase& base)
{
if (hasVariableFrames(base))
return;
bool contiguous = isContiguous(base);
AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs;
SInt64 delta = descs[kMask].mStartOffset + descs[kMask].mDataByteSize - descs[0].mStartOffset;
SInt64 baseOffset = descs[0].mStartOffset;
base.mBaseOffset = baseOffset;
if (delta <= 65535LL) {
COMPRESS_TYPE(Tiny, UInt16)
} else if (delta <= 4294967295LL && largestPacket(base) <= 65535) {
COMPRESS_TYPE(Small, UInt32)
} else {
COMPRESS_TYPE(Big, SInt64)
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -0,0 +1,186 @@
/*
File: CompressedPacketTable.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include <iterator>
#include <vector>
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreAudio/CoreAudioTypes.h>
#else
#include "CoreAudioTypes.h"
#endif
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct AudioStreamPacketDescriptionExtended : AudioStreamPacketDescription
{
SInt64 mFrameOffset; // this is the sum of the mVariableFramesInPacket up to this point so we can binary search.
};
typedef struct AudioStreamPacketDescriptionExtended AudioStreamPacketDescriptionExtended;
inline bool operator < (const AudioStreamPacketDescriptionExtended& a, const AudioStreamPacketDescriptionExtended& b)
{
return a.mFrameOffset < b.mFrameOffset;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CompressedPacketTable
{
public:
CompressedPacketTable(UInt32 inFramesPerPacket) : mSize(0), mFramesPerPacket(inFramesPerPacket) {}
~CompressedPacketTable();
SInt64 size() const { return mSize; }
void push_back(const AudioStreamPacketDescriptionExtended& inDesc);
const AudioStreamPacketDescriptionExtended operator[](SInt64 inPacketIndex) const;
const AudioStreamPacketDescriptionExtended front() const { return (*this)[0]; }
const AudioStreamPacketDescriptionExtended back() const { return (*this)[mSize-1]; }
//SInt64 PacketForByte(SInt64 inByteOffset) const;
SInt64 ByteForPacket(SInt64 inPacketIndex) const { return (*this)[inPacketIndex].mStartOffset; }
class iterator {
public:
typedef std::input_iterator_tag iterator_category;
typedef iterator pointer;
typedef SInt64 difference_type;
typedef AudioStreamPacketDescriptionExtended value_type;
typedef value_type& reference;
iterator() : mTable(NULL), mIndex(0) {}
iterator(const CompressedPacketTable* table, SInt64 index) : mTable(table), mIndex(index) {}
iterator(const iterator& that) : mTable(that.mTable), mIndex(that.mIndex) {}
iterator& operator=(const iterator& that) { mTable = that.mTable; mIndex = that.mIndex; return *this; }
const AudioStreamPacketDescriptionExtended operator*() const { return (*mTable)[mIndex]; }
const AudioStreamPacketDescriptionExtended* const operator->() { mValue = (*mTable)[mIndex]; return &mValue; }
iterator& operator++() { ++mIndex; return *this; }
iterator& operator--() { --mIndex; return *this; }
SInt64 operator-(const iterator& that) { return mIndex - that.mIndex; }
const iterator operator-(SInt64 index) { return iterator(mTable, mIndex - index); }
const iterator operator+(SInt64 index) { return iterator(mTable, mIndex + index); }
bool operator==(const iterator& that) { return mIndex == that.mIndex; }
bool operator!=(const iterator& that) { return mIndex != that.mIndex; }
bool operator>(const iterator& that) { return mIndex > that.mIndex; }
bool operator<(const iterator& that) { return mIndex < that.mIndex; }
private:
const CompressedPacketTable* mTable;
SInt64 mIndex;
AudioStreamPacketDescriptionExtended mValue; // in order to support operator-> .
};
iterator begin() const { return iterator(this, 0); }
iterator end() const { return iterator(this, mSize); }
private:
struct TinyContiguousPacketDescription
{
UInt16 mNextOffset;
};
struct TinyDiscontiguousPacketDescription : TinyContiguousPacketDescription
{
UInt16 mDataByteSize;
};
// There could be a 24 bit packet description. But ALAC is who usually needs SmallContiguousPacketDescription and
// it already uses 8x fewer packet descriptions than AAC due to the mFramesPerPacket being 8x greater.
// So there isn't as great a need for saving space. 4 bytes per packet is OK for ALAC.
struct SmallContiguousPacketDescription
{
UInt32 mNextOffset;
};
struct SmallDiscontiguousPacketDescription : SmallContiguousPacketDescription
{
UInt16 mDataByteSize;
};
struct BigContiguousPacketDescription
{
UInt64 mNextOffset;
};
struct BigDiscontiguousPacketDescription : BigContiguousPacketDescription
{
UInt32 mDataByteSize;
};
struct PacketBase
{
SInt64 mBaseOffset;
UInt8 mDescType;
void* mDescs;
};
enum {
kTinyContiguousPacketDescription,
kTinyDiscontiguousPacketDescription,
kSmallContiguousPacketDescription,
kSmallDiscontiguousPacketDescription,
kBigContiguousPacketDescription,
kBigDiscontiguousPacketDescription,
kExtendedPacketDescription
};
static const UInt32 kShift;
static const UInt32 kMask;
bool isContiguous(PacketBase& base);
bool hasVariableFrames(PacketBase& base);
UInt32 largestPacket(PacketBase& base);
void Compress(PacketBase& base);
private:
std::vector<PacketBase> mBases;
UInt64 mSize;
UInt32 mFramesPerPacket;
};

View File

@@ -0,0 +1,689 @@
/*
File: DataSource.cpp
Abstract: DataSource.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "DataSource.h"
#if TARGET_OS_WIN32
#include <io.h>
#else
#include <unistd.h>
#include <fcntl.h>
#endif
#include <sys/stat.h>
#include <algorithm>
#define VERBOSE 0
//////////////////////////////////////////////////////////////////////////////////////////
const UInt16 kPositionModeMask = 3;
DataSource::DataSource(Boolean inCloseOnDelete)
: mCloseOnDelete(inCloseOnDelete)
{
}
DataSource::~DataSource()
{
}
SInt64 DataSource::CalcOffset( UInt16 positionMode,
SInt64 positionOffset,
SInt64 currentOffset,
SInt64 size)
{
SInt64 newOffset = 0;
switch (positionMode & kPositionModeMask) {
//case fsAtMark : newOffset = currentOffset; break;
case SEEK_SET : newOffset = positionOffset; break;
case SEEK_END : newOffset = size + positionOffset; break;
case SEEK_CUR : newOffset = positionOffset + currentOffset; break;
}
return newOffset;
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
#if 0
MacFile_DataSource::MacFile_DataSource( FSIORefNum inForkRefNum, SInt8 inPermissions, Boolean inCloseOnDelete)
: DataSource(inCloseOnDelete), mFileNum(inForkRefNum), mPermissions(inPermissions)
{
}
MacFile_DataSource::~MacFile_DataSource()
{
if (mCloseOnDelete) FSCloseFork(mFileNum);
}
OSStatus MacFile_DataSource::GetSize(SInt64& outSize)
{
outSize = -1; // in case of error
OSStatus err = FSGetForkSize(mFileNum, &outSize);
return err;
}
OSStatus MacFile_DataSource::GetPos(SInt64& outPos) const
{
return FSGetForkPosition(mFileNum, &outPos);
}
OSStatus MacFile_DataSource::SetSize(SInt64 inSize)
{
return FSSetForkSize(mFileNum, SEEK_SET, inSize);
}
OSStatus MacFile_DataSource::ReadBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)
{
if (actualCount) *actualCount = 0;
if (!buffer) return kAudio_ParamError;
ByteCount bc_actualCount = 0;
OSStatus err = FSReadFork(mFileNum, positionMode, positionOffset, requestCount, buffer, &bc_actualCount);
if (actualCount) *actualCount = (UInt32)bc_actualCount;
return err;
}
OSStatus MacFile_DataSource::WriteBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount)
{
if (!buffer) return kAudio_ParamError;
ByteCount bc_actualCount = 0;
OSStatus err = FSWriteFork(mFileNum, positionMode, positionOffset, requestCount, buffer, &bc_actualCount);
if (actualCount) *actualCount = (UInt32)bc_actualCount;
return err;
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////
#define kAudioFileNoCacheMask 0x20
UnixFile_DataSource::UnixFile_DataSource( int inFD, SInt8 inPermissions, Boolean inCloseOnDelete)
: DataSource(inCloseOnDelete), mFileD(inFD), mPermissions(inPermissions), mNoCache(0), mCachedSize(-1), mFilePointer(0)
{
}
UnixFile_DataSource::~UnixFile_DataSource()
{
if (mCloseOnDelete) close(mFileD);
}
OSStatus UnixFile_DataSource::GetSize(SInt64& outSize)
{
#if 0 // 6764274 using the cached file size causes a regression for apps that play a file while writing to it.
if (mCachedSize >= 0) {
outSize = mCachedSize;
return noErr;
}
#endif
outSize = -1; // in case of error
struct stat stbuf;
if (fstat (mFileD, &stbuf) == -1) return kAudio_FileNotFoundError;
outSize = mCachedSize = stbuf.st_size;
return noErr;
}
OSStatus UnixFile_DataSource::SetSize(SInt64 inSize)
{
mCachedSize = -1;
#if TARGET_OS_WIN32
if (chsize (mFileD, inSize)) return kAudioFilePermissionsError;
#else
if (ftruncate (mFileD, inSize) == -1) return kAudioFilePermissionsError;
#endif
mCachedSize = inSize;
return noErr;
}
OSStatus UnixFile_DataSource::GetPos(SInt64& outPos) const
{
outPos = mFilePointer;
return noErr;
}
SInt64 UnixFile_DataSource::UFCurrentOffset (UInt16 positionMode,
SInt64 positionOffset)
{
SInt64 offset = -1;
switch (positionMode & kPositionModeMask)
{
/*case fsAtMark :
{
SInt64 pos;
OSStatus result = GetPos (pos);
if (result) return result;
offset = pos;
break;
}*/
case SEEK_SET :
{
offset = positionOffset;
break;
}
case SEEK_END :
{
SInt64 size;
OSStatus result = GetSize (size);
if (result) return result;
offset = size + positionOffset;
break;
}
case SEEK_CUR :
{
SInt64 pos;
OSStatus result = GetPos (pos);
if (result) return result;
offset = positionOffset + pos;
break;
}
}
return offset;
}
OSStatus UnixFile_DataSource::ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)
{
if (actualCount) *actualCount = 0;
if (!buffer) return kAudio_ParamError;
// can't use current offset as we need to go to the disk too much
SInt64 offset = UFCurrentOffset (positionMode, positionOffset);
if (offset < 0) return kAudioFilePositionError;
#if 0 // 6571050 fstat-ing the file every read causes a performance regression
// 5931571 check that read may exceed eof and curtail it.
do {
SInt64 size;
OSStatus serr = GetSize(size);
if (serr) break;
SInt64 remain = size - offset;
if (remain < 0) requestCount = 0;
else if (requestCount > remain) requestCount = remain;
} while (false);
#endif
if (requestCount <= 0) {
if (actualCount) *actualCount = 0;
return noErr;
}
#if !TARGET_OS_WIN32
UInt32 noCache = positionMode & kAudioFileNoCacheMask ? 1 : 0;
if (noCache != mNoCache) {
mNoCache = noCache;
fcntl(mFileD, F_NOCACHE, mNoCache);
}
#endif
size_t readBytes = requestCount;
#if TARGET_OS_WIN32
lseek(mFileD, offset, SEEK_SET);
int numBytes = read (mFileD, buffer, readBytes);
#else
ssize_t numBytes = pread (mFileD, buffer, readBytes, offset);
#endif
if (numBytes == -1) return kAudioFilePositionError;
mFilePointer = offset + numBytes;
if (actualCount) *actualCount = (UInt32)numBytes;
return noErr;
}
OSStatus UnixFile_DataSource::WriteBytes(UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount)
{
if (!buffer) return kAudio_ParamError;
// can't use current offset as we need to go to the disk too much
SInt64 offset = UFCurrentOffset (positionMode, positionOffset);
if (offset < 0) return kAudioFilePositionError;
mCachedSize = -1;
size_t writeBytes = requestCount;
#if !TARGET_OS_WIN32
UInt32 noCache = positionMode & kAudioFileNoCacheMask ? 1 : 0;
if (noCache != mNoCache) {
mNoCache = noCache;
fcntl(mFileD, F_NOCACHE, mNoCache);
}
#endif
#if TARGET_OS_WIN32
lseek(mFileD, offset, SEEK_SET);
int numBytes = write (mFileD, buffer, writeBytes);
#else
ssize_t numBytes = pwrite (mFileD, buffer, writeBytes, offset);
#endif
if (numBytes == -1) return kAudioFilePositionError;
mFilePointer = offset + numBytes;
if (actualCount) *actualCount = (UInt32)numBytes;
return noErr;
}
//////////////////////////////////////////////////////////////////////////////////////////
#define NO_CACHE 0
OSStatus Cached_DataSource::ReadFromHeaderCache(
SInt64 offset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)
{
if (actualCount) *actualCount = 0;
OSStatus err = noErr;
ByteCount theActualCount = 0;
#if VERBOSE
printf("read from header %lld %lu %lld %lu\n", offset, requestCount, 0LL, mHeaderCacheSize);
#endif
if (!mHeaderCache())
{
mHeaderCache.allocBytes(mHeaderCacheSize, true);
err = mDataSource->ReadBytes(SEEK_SET, 0, mHeaderCacheSize, mHeaderCache(), &mHeaderCacheSize);
if (err == kAudioFileEndOfFileError) err = noErr;
if (err) return err;
}
ByteCount firstPart = std::min((ByteCount)requestCount, (ByteCount)(mHeaderCacheSize - offset));
ByteCount secondPart = requestCount - firstPart;
memcpy(buffer, mHeaderCache + (ByteCount)offset, firstPart);
theActualCount = firstPart;
if (secondPart) {
UInt32 secondPartActualCount = 0;
err = mDataSource->ReadBytes(SEEK_SET, mHeaderCacheSize, static_cast<UInt32>(secondPart), (char*)buffer + firstPart, &secondPartActualCount);
theActualCount += secondPartActualCount;
}
if (actualCount) *actualCount = (UInt32)theActualCount;
mOffset = offset + theActualCount;
return err;
}
OSStatus Cached_DataSource::ReadBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)
{
if (actualCount) *actualCount = 0;
OSStatus err = noErr;
SInt64 size;
UInt32 theActualCount = 0;
if (!buffer) return kAudio_ParamError;
if ((positionMode & kPositionModeMask) != SEEK_END) size = 0; // not used in this case
else
{
err = GetSize(size);
if (err) return err;
}
SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
if (offset < 0) return kAudioFilePositionError;
if (offset < mHeaderCacheSize) {
return ReadFromHeaderCache(offset, requestCount, buffer, actualCount);
}
#if NO_CACHE
err = mDataSource->ReadBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount);
mOffset = offset + theActualCount;
#else
SInt64 cacheEnd = mBodyCacheOffset + mBodyCacheCurSize;
if (mBodyCache() && requestCount < mBodyCacheSize && offset >= mBodyCacheOffset && offset < cacheEnd)
{
if (offset + requestCount <= cacheEnd)
{
// request is entirely within cache
#if VERBOSE
printf("request is entirely within cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
#endif
memcpy(buffer, mBodyCache + (size_t)(offset - mBodyCacheOffset), requestCount);
theActualCount = requestCount;
}
else
{
// part of request is within cache. copy, read next cache block, copy.
#if VERBOSE
printf("part of request is within cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
#endif
// copy first part.
ByteCount firstPart = (ByteCount)(cacheEnd - offset);
ByteCount secondPart = requestCount - firstPart;
#if VERBOSE
printf("memcpy offset %lld mBodyCacheOffset %lld offset - mBodyCacheOffset %lld firstPart %lu requestCount %lu\n",
offset, mBodyCacheOffset, offset - mBodyCacheOffset, firstPart, requestCount);
#endif
memcpy(buffer, mBodyCache + (size_t)(offset - mBodyCacheOffset), firstPart);
theActualCount = static_cast<UInt32>(firstPart);
// read new block
SInt64 nextOffset = mBodyCacheOffset + mBodyCacheCurSize;
err = mDataSource->ReadBytes(SEEK_SET, nextOffset, mBodyCacheSize, mBodyCache(), &mBodyCacheCurSize);
if (err == kAudioFileEndOfFileError) err = noErr;
if (err) goto leave;
mBodyCacheOffset = nextOffset;
// copy second part
secondPart = std::min(secondPart, (ByteCount)mBodyCacheCurSize);
if (secondPart) memcpy((char*)buffer + firstPart, mBodyCache(), secondPart);
theActualCount = static_cast<UInt32>(firstPart + secondPart);
}
}
else
{
if (requestCount > mBodyCacheSize)
{
#if VERBOSE
printf("large request %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
#endif
// the request is larger than we normally cache, just do a read and don't cache.
err = mDataSource->ReadBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount);
mOffset = offset + theActualCount;
}
else
{
// request is outside cache. read new block.
#if VERBOSE
printf("request is outside cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
#endif
if (!mBodyCache())
{
mBodyCache.allocBytes(mBodyCacheSize, true);
#if VERBOSE
printf("alloc mBodyCache %08X\n", mBodyCache());
#endif
}
mBodyCacheOffset = offset;
err = mDataSource->ReadBytes(SEEK_SET, mBodyCacheOffset, mBodyCacheSize, mBodyCache(), &mBodyCacheCurSize);
#if VERBOSE
printf("read %08X %d mBodyCacheOffset %lld %lu %lu\n", err, err, mBodyCacheOffset, mBodyCacheSize, mBodyCacheCurSize);
#endif
if (err == kAudioFileEndOfFileError) err = noErr;
if (err) return err;
theActualCount = std::min(requestCount, mBodyCacheCurSize);
memcpy(buffer, mBodyCache(), theActualCount);
}
}
leave:
#endif
if (actualCount) *actualCount = (UInt32)theActualCount;
#if VERBOSE
printf("<<read err %d actualCount %lu\n", err, *actualCount);
#endif
return err;
}
OSStatus Cached_DataSource::WriteBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount)
{
OSStatus err = noErr;
SInt64 size;
if (!buffer) return kAudio_ParamError;
if ((positionMode & kPositionModeMask) != SEEK_END) size = 0; // not used in this case
else
{
err = GetSize(size);
if (err) return err;
}
SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
if (offset < 0) return kAudioFilePositionError;
if (mHeaderCache() && offset < mHeaderCacheSize)
{
// header cache write through
ByteCount firstPart = std::min((ByteCount)requestCount, (ByteCount)(mHeaderCacheSize - offset));
#if VERBOSE
printf("header cache write through %lu %lu\n", mHeaderCacheSize, firstPart);
#endif
memcpy(mHeaderCache + (size_t)offset, buffer, firstPart);
}
#if VERBOSE
printf("write %lld %lu %lld %d %lld\n", offset, requestCount, mOffset, positionMode, positionOffset);
#endif
SInt64 cacheEnd = mBodyCacheOffset + mBodyCacheCurSize;
if (mBodyCache() && offset >= mBodyCacheOffset && offset < cacheEnd)
{
// body cache write through
ByteCount firstPart = std::min((SInt64)requestCount, cacheEnd - offset);
#if VERBOSE
printf("body cache write through %lld %lu %lld %lu\n", mBodyCacheOffset, mBodyCacheCurSize, offset, firstPart);
#endif
memcpy(mBodyCache + (offset - mBodyCacheOffset), buffer, firstPart);
}
UInt32 theActualCount;
err = mDataSource->WriteBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount);
mOffset = offset + theActualCount;
if (actualCount) *actualCount = (UInt32)theActualCount;
return err;
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
Seekable_DataSource::Seekable_DataSource( void * inClientData,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc)
: DataSource(false), mClientData(inClientData), mReadFunc(inReadFunc), mWriteFunc(inWriteFunc),
mSizeFunc(inGetSizeFunc), mSetSizeFunc(inSetSizeFunc)
{
}
Seekable_DataSource::~Seekable_DataSource()
{
}
OSStatus Seekable_DataSource::GetSize(SInt64& outSize)
{
if (!mSizeFunc) {
outSize = LLONG_MAX;
} else {
outSize = (*mSizeFunc)(mClientData);
}
return noErr;
}
OSStatus Seekable_DataSource::SetSize(SInt64 inSize)
{
if (!mSetSizeFunc) return kAudioFileOperationNotSupportedError;
return (*mSetSizeFunc)(mClientData, inSize);
}
OSStatus Seekable_DataSource::ReadBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)
{
OSStatus err;
if (actualCount) *actualCount = 0;
if (!mReadFunc) return kAudioFileOperationNotSupportedError;
if (!buffer) return kAudio_ParamError;
positionMode &= kPositionModeMask;
SInt64 size;
err = GetSize(size);
if (err) return err;
SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
// request is outside bounds of file
if (offset < 0)
return kAudioFilePositionError;
if (offset >= size)
return kAudioFileEndOfFileError;
// reduce request if it exceeds the amount available
requestCount = static_cast<UInt32>(std::min((SInt64)requestCount, size - offset));
UInt32 theActualCount = 0;
err = (*mReadFunc)(mClientData, offset, requestCount, buffer, &theActualCount);
if (actualCount) *actualCount = theActualCount;
mOffset = offset + theActualCount;
return err;
}
OSStatus Seekable_DataSource::WriteBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount)
{
OSStatus err;
if (!mWriteFunc) return kAudioFileOperationNotSupportedError;
if (!buffer) return kAudio_ParamError;
SInt64 size;
positionMode &= kPositionModeMask;
if (positionMode != SEEK_END) size = 0; // not used in this case
else
{
err = GetSize(size);
if (err) return err;
}
SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
if (offset < 0) return kAudioFilePositionError;
UInt32 theActualCount;
err = (*mWriteFunc)(mClientData, offset, requestCount, buffer, &theActualCount);
if (err) return err;
if (actualCount) *actualCount = theActualCount;
mOffset = offset + theActualCount;
return noErr;
}
//////////////////////////////////////////////////////////////////////////////////////////
OSStatus Buffer_DataSource::ReadBytes(
UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)
{
if (actualCount) *actualCount = 0;
SInt64 offsetWithinBuffer = CalcOffset(positionMode, positionOffset, mOffset, mDataByteSize + mStartOffset) - mStartOffset;
if (offsetWithinBuffer < 0 || offsetWithinBuffer >= mDataByteSize) return kAudioFilePositionError;
SInt64 bytesAfterOffset = mDataByteSize - offsetWithinBuffer;
SInt64 theActualCount = std::min(bytesAfterOffset, (SInt64)requestCount);
if (theActualCount <= 0) {
if (actualCount) *actualCount = 0;
return kAudio_ParamError;
}
memcpy(buffer, mData + offsetWithinBuffer, theActualCount);
if (actualCount) *actualCount = static_cast<UInt32>(theActualCount);
mOffset = offsetWithinBuffer + theActualCount;
return noErr;
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,372 @@
/*
File: DataSource.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __DataSource_h__
#define __DataSource_h__
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioToolbox/AudioFile.h>
#else
#include <ConditionalMacros.h>
#include "AudioFile.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdexcept>
#include "CAAutoDisposer.h"
//////////////////////////////////////////////////////////////////////////////////////////
class DataSource
{
public:
DataSource(Boolean inCloseOnDelete);
virtual ~DataSource();
virtual OSStatus GetSize32(UInt32& outSize)
{
SInt64 size64;
OSStatus err = GetSize(size64);
if (err) return err;
if (size64 > 0x00000000FFFFffffLL) return kAudioFileDoesNotAllow64BitDataSizeError;
outSize = (UInt32)size64;
return noErr;
}
virtual OSStatus GetSize(SInt64& outSize) =0;
virtual OSStatus SetSize(SInt64 inSize)=0;
virtual OSStatus GetPos(SInt64& outPos) const=0;
/* non seekable data sources should use fsAtMark for the positionMode (or SEEK_CUR with offset zero,
or SEEK_SET with offset equal to the current position in the stream, in other words no seeking from the
current position is allowed.)
*/
virtual OSStatus ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount)=0;
virtual OSStatus WriteBytes(UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount)=0;
virtual void SetCloseOnDelete(Boolean inFlag) { mCloseOnDelete = inFlag; }
virtual Boolean CanSeek() const=0;
virtual Boolean CanGetSize() const=0;
virtual Boolean CanSetSize() const=0;
virtual Boolean CanRead() const=0;
virtual Boolean CanWrite() const=0;
protected:
Boolean mCloseOnDelete;
/* utility method */
SInt64 CalcOffset( UInt16 positionMode,
SInt64 positionOffset,
SInt64 currentOffset,
SInt64 size);
};
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/*
Initialize with a Macintosh file fork ref num as obtained from FSOpenFork.
*/
#if 0
class MacFile_DataSource : public DataSource
{
FSIORefNum mFileNum;
SInt8 mPermissions;
public:
MacFile_DataSource( FSIORefNum inForkRefNum, SInt8 inPermissions, Boolean inCloseOnDelete);
virtual ~MacFile_DataSource();
virtual OSStatus GetSize(SInt64& outSize);
virtual OSStatus GetPos(SInt64& outPos) const;
virtual OSStatus SetSize(SInt64 inSize);
virtual OSStatus ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount);
virtual OSStatus WriteBytes(UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount);
virtual Boolean CanSeek() const { return true; }
virtual Boolean CanGetSize() const { return true; }
virtual Boolean CanSetSize() const { return true; }
virtual Boolean CanRead() const { return mPermissions & kAudioFileReadPermission; }
virtual Boolean CanWrite() const { return mPermissions & kAudioFileWritePermission; }
};
#endif
class UnixFile_DataSource : public DataSource
{
int mFileD;
SInt8 mPermissions;
UInt32 mNoCache;
SInt64 mCachedSize;
SInt64 mFilePointer;
public:
UnixFile_DataSource( int inFD, SInt8 inPermissions, Boolean inCloseOnDelete);
virtual ~UnixFile_DataSource();
virtual OSStatus GetSize(SInt64& outSize);
virtual OSStatus GetPos(SInt64& outPos) const;
virtual OSStatus SetSize(SInt64 inSize);
virtual OSStatus ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount);
virtual OSStatus WriteBytes(UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount);
virtual Boolean CanSeek() const { return true; }
virtual Boolean CanGetSize() const { return true; }
virtual Boolean CanSetSize() const { return true; }
virtual Boolean CanRead() const { return mPermissions & kAudioFileReadPermission; }
virtual Boolean CanWrite() const { return mPermissions & kAudioFileWritePermission; }
private:
SInt64 UFCurrentOffset (UInt16 positionMode,
SInt64 positionOffset);
};
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/*
A wrapper that caches the wrapped source's header.
*/
class Cached_DataSource : public DataSource
{
DataSource* mDataSource;
CAAutoFree<UInt8> mHeaderCache;
UInt32 mHeaderCacheSize;
CAAutoFree<UInt8> mBodyCache;
UInt32 mBodyCacheSize;
UInt32 mBodyCacheCurSize;
SInt64 mBodyCacheOffset;
SInt64 mOffset;
Boolean mOwnDataSource;
public:
Cached_DataSource(DataSource* inDataSource, UInt32 inHeaderCacheSize = 4096, UInt32 inBodyCacheSize = 32768, Boolean inOwnDataSource = true)
: DataSource(false),
mDataSource(inDataSource), mHeaderCacheSize(inHeaderCacheSize),
mBodyCacheSize(inBodyCacheSize), mBodyCacheCurSize(0), mBodyCacheOffset(-1),
mOffset(0),
mOwnDataSource(inOwnDataSource)
{
}
virtual ~Cached_DataSource()
{
if (mOwnDataSource) delete mDataSource;
}
virtual OSStatus GetSize(SInt64& outSize) { return mDataSource->GetSize(outSize); }
virtual OSStatus GetPos(SInt64& outPos) const { return mDataSource->GetPos(outPos); }
virtual OSStatus SetSize(SInt64 inSize) { return mDataSource->SetSize(inSize); }
virtual OSStatus ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount);
virtual OSStatus WriteBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount);
OSStatus ReadFromHeaderCache( SInt64 offset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount);
virtual Boolean CanSeek() const { return mDataSource->CanSeek(); }
virtual Boolean CanGetSize() const { return mDataSource->CanGetSize(); }
virtual Boolean CanSetSize() const { return mDataSource->CanSetSize(); }
virtual Boolean CanRead() const { return mDataSource->CanRead(); }
virtual Boolean CanWrite() const { return mDataSource->CanWrite(); }
};
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/* This class calls user supplied routines on demand. */
class Seekable_DataSource : public DataSource
{
void * mClientData;
SInt64 mOffset;
AudioFile_ReadProc mReadFunc;
AudioFile_WriteProc mWriteFunc;
AudioFile_GetSizeProc mSizeFunc;
AudioFile_SetSizeProc mSetSizeFunc;
public:
Seekable_DataSource( void * inClientData,
AudioFile_ReadProc inReadFunc,
AudioFile_WriteProc inWriteFunc,
AudioFile_GetSizeProc inGetSizeFunc,
AudioFile_SetSizeProc inSetSizeFunc
);
virtual ~Seekable_DataSource();
virtual OSStatus GetSize(SInt64& outSize);
virtual OSStatus GetPos(SInt64& outPos) const { outPos = mOffset; return noErr; };
virtual OSStatus SetSize(SInt64 inSize);
virtual OSStatus ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount);
virtual OSStatus WriteBytes(UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount);
virtual Boolean CanSeek() const { return true; }
virtual Boolean CanGetSize() const { return mSizeFunc != 0; }
virtual Boolean CanSetSize() const { return mSetSizeFunc != 0; }
virtual Boolean CanRead() const { return mReadFunc != 0; }
virtual Boolean CanWrite() const { return mWriteFunc != 0; }
};
//////////////////////////////////////////////////////////////////////////////////////////
class Buffer_DataSource : public DataSource
{
UInt32 mDataByteSize;
const char * mData;
SInt64 mStartOffset;
SInt64 mOffset;
public:
Buffer_DataSource( UInt32 inDataByteSize,
const void * inData,
SInt64 inStartOffset = 0
) : DataSource(false), mDataByteSize(inDataByteSize), mData((const char*)inData), mStartOffset(inStartOffset), mOffset(mStartOffset) {}
virtual ~Buffer_DataSource() {}
virtual OSStatus GetSize(SInt64& outSize) { outSize = mDataByteSize + mStartOffset; return noErr; }
virtual OSStatus GetPos(SInt64& outPos) const { outPos = mOffset; return noErr; };
virtual OSStatus SetSize(SInt64 inSize) { throw std::runtime_error("not writable"); }
virtual OSStatus ReadBytes( UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
void *buffer,
UInt32* actualCount);
virtual OSStatus WriteBytes(UInt16 positionMode,
SInt64 positionOffset,
UInt32 requestCount,
const void *buffer,
UInt32* actualCount) { throw std::runtime_error("not writable"); }
virtual Boolean CanSeek() const { return true; }
virtual Boolean CanGetSize() const { return true; }
virtual Boolean CanSetSize() const { return false; }
virtual Boolean CanRead() const { return true; }
virtual Boolean CanWrite() const { return false; }
};
//////////////////////////////////////////////////////////////////////////////////////////
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,438 @@
/*
File: AUDispatch.cpp
Abstract: AUDispatch.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUBase.h"
#include "CAXException.h"
#include "AUDispatch.h"
#if TARGET_OS_MAC
#if __LP64__
// comp instance, parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_index + 1];
#else
// parameters in reverse order, then comp instance
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_nparams - 1 - _index];
#endif
#elif TARGET_OS_WIN32
// (no comp instance), parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_index];
#endif
OSStatus AUBase::ComponentEntryDispatch(ComponentParameters *params, AUBase *This)
{
if (This == NULL) return kAudio_ParamError;
OSStatus result = noErr;
switch (params->what) {
case kComponentCanDoSelect:
switch (GetSelectorForCanDo(params)) {
// any selectors
case kAudioUnitInitializeSelect:
case kAudioUnitUninitializeSelect:
case kAudioUnitGetPropertyInfoSelect:
case kAudioUnitGetPropertySelect:
case kAudioUnitSetPropertySelect:
case kAudioUnitAddPropertyListenerSelect:
#if (!__LP64__)
case kAudioUnitRemovePropertyListenerSelect:
#endif
case kAudioUnitGetParameterSelect:
case kAudioUnitSetParameterSelect:
case kAudioUnitResetSelect:
result = 1;
break;
// v1 selectors
// v2 selectors
case kAudioUnitRemovePropertyListenerWithUserDataSelect:
case kAudioUnitAddRenderNotifySelect:
case kAudioUnitRemoveRenderNotifySelect:
case kAudioUnitScheduleParametersSelect:
case kAudioUnitRenderSelect:
result = (This->AudioUnitAPIVersion() > 1);
break;
default:
return ComponentBase::ComponentEntryDispatch(params, This);
}
break;
case kAudioUnitInitializeSelect:
{
CAMutex::Locker lock2(This->GetMutex());
result = This->DoInitialize();
}
break;
case kAudioUnitUninitializeSelect:
{
CAMutex::Locker lock2(This->GetMutex());
This->DoCleanup();
result = noErr;
}
break;
case kAudioUnitGetPropertyInfoSelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitPropertyID, pinID, 0, 5);
PARAM(AudioUnitScope, pinScope, 1, 5);
PARAM(AudioUnitElement, pinElement, 2, 5);
PARAM(UInt32 *, poutDataSize, 3, 5);
PARAM(Boolean *, poutWritable, 4, 5);
// pass our own copies so that we assume responsibility for testing
// the caller's pointers against null and our C++ classes can
// always assume they're non-null
UInt32 dataSize;
Boolean writable;
result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable);
if (poutDataSize != NULL)
*poutDataSize = dataSize;
if (poutWritable != NULL)
*poutWritable = writable;
}
break;
case kAudioUnitGetPropertySelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitPropertyID, pinID, 0, 5);
PARAM(AudioUnitScope, pinScope, 1, 5);
PARAM(AudioUnitElement, pinElement, 2, 5);
PARAM(void *, poutData, 3, 5);
PARAM(UInt32 *, pioDataSize, 4, 5);
UInt32 actualPropertySize, clientBufferSize;
Boolean writable;
char *tempBuffer;
void *destBuffer;
if (pioDataSize == NULL) {
ca_debug_string("AudioUnitGetProperty: null size pointer");
result = kAudio_ParamError;
goto finishGetProperty;
}
if (poutData == NULL) {
UInt32 dataSize;
result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable);
*pioDataSize = dataSize;
goto finishGetProperty;
}
clientBufferSize = *pioDataSize;
if (clientBufferSize == 0)
{
ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry");
// $$$ or should we allow this as a shortcut for finding the size?
result = kAudio_ParamError;
goto finishGetProperty;
}
result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement,
actualPropertySize, writable);
if (result)
goto finishGetProperty;
if (clientBufferSize < actualPropertySize)
{
tempBuffer = new char[actualPropertySize];
destBuffer = tempBuffer;
} else {
tempBuffer = NULL;
destBuffer = poutData;
}
result = This->DispatchGetProperty(pinID, pinScope, pinElement, destBuffer);
if (result == noErr) {
if (clientBufferSize < actualPropertySize && tempBuffer != NULL)
{
memcpy(poutData, tempBuffer, clientBufferSize);
delete[] tempBuffer;
// pioDataSize remains correct, the number of bytes we wrote
} else
*pioDataSize = actualPropertySize;
} else
*pioDataSize = 0;
finishGetProperty:
;
}
break;
case kAudioUnitSetPropertySelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitPropertyID, pinID, 0, 5);
PARAM(AudioUnitScope, pinScope, 1, 5);
PARAM(AudioUnitElement, pinElement, 2, 5);
PARAM(const void *, pinData, 3, 5);
PARAM(UInt32, pinDataSize, 4, 5);
if (pinData && pinDataSize)
result = This->DispatchSetProperty(pinID, pinScope, pinElement, pinData, pinDataSize);
else {
if (pinData == NULL && pinDataSize == 0) {
result = This->DispatchRemovePropertyValue (pinID, pinScope, pinElement);
} else {
if (pinData == NULL) {
ca_debug_string("AudioUnitSetProperty: inData == NULL");
result = kAudio_ParamError;
goto finishSetProperty;
}
if (pinDataSize == 0) {
ca_debug_string("AudioUnitSetProperty: inDataSize == 0");
result = kAudio_ParamError;
goto finishSetProperty;
}
}
}
finishSetProperty:
;
}
break;
case kAudioUnitAddPropertyListenerSelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitPropertyID, pinID, 0, 3);
PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3);
PARAM(void *, pinProcRefCon, 2, 3);
result = This->AddPropertyListener(pinID, pinProc, pinProcRefCon);
}
break;
#if (!__LP64__)
case kAudioUnitRemovePropertyListenerSelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitPropertyID, pinID, 0, 2);
PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 2);
result = This->RemovePropertyListener(pinID, pinProc, NULL, false);
}
break;
#endif
case kAudioUnitRemovePropertyListenerWithUserDataSelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitPropertyID, pinID, 0, 3);
PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3);
PARAM(void *, pinProcRefCon, 2, 3);
result = This->RemovePropertyListener(pinID, pinProc, pinProcRefCon, true);
}
break;
case kAudioUnitAddRenderNotifySelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AURenderCallback, pinProc, 0, 2);
PARAM(void *, pinProcRefCon, 1, 2);
result = This->SetRenderNotification (pinProc, pinProcRefCon);
}
break;
case kAudioUnitRemoveRenderNotifySelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AURenderCallback, pinProc, 0, 2);
PARAM(void *, pinProcRefCon, 1, 2);
result = This->RemoveRenderNotification (pinProc, pinProcRefCon);
}
break;
case kAudioUnitGetParameterSelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitParameterID, pinID, 0, 4);
PARAM(AudioUnitScope, pinScope, 1, 4);
PARAM(AudioUnitElement, pinElement, 2, 4);
PARAM(AudioUnitParameterValue *, poutValue, 3, 4);
result = (poutValue == NULL ? kAudio_ParamError : This->GetParameter(pinID, pinScope, pinElement, *poutValue));
}
break;
case kAudioUnitSetParameterSelect:
{
CAMutex::Locker lock(This->GetMutex()); // is this realtime or no???
PARAM(AudioUnitParameterID, pinID, 0, 5);
PARAM(AudioUnitScope, pinScope, 1, 5);
PARAM(AudioUnitElement, pinElement, 2, 5);
PARAM(AudioUnitParameterValue, pinValue, 3, 5);
PARAM(UInt32, pinBufferOffsetInFrames, 4, 5);
result = This->SetParameter(pinID, pinScope, pinElement, pinValue, pinBufferOffsetInFrames);
}
break;
case kAudioUnitScheduleParametersSelect:
{
CAMutex::Locker lock(This->GetMutex()); // is this realtime or no???
if (This->AudioUnitAPIVersion() > 1)
{
PARAM(AudioUnitParameterEvent *, pinParameterEvent, 0, 2);
PARAM(UInt32, pinNumParamEvents, 1, 2);
result = This->ScheduleParameter (pinParameterEvent, pinNumParamEvents);
} else
result = badComponentSelector;
}
break;
case kAudioUnitRenderSelect:
{
// realtime; no lock
{
PARAM(AudioUnitRenderActionFlags *, pinActionFlags, 0, 5);
PARAM(const AudioTimeStamp *, pinTimeStamp, 1, 5);
PARAM(UInt32, pinOutputBusNumber, 2, 5);
PARAM(UInt32, pinNumberFrames, 3, 5);
PARAM(AudioBufferList *, pioData, 4, 5);
AudioUnitRenderActionFlags tempFlags;
if (pinTimeStamp == NULL || pioData == NULL)
result = kAudio_ParamError;
else {
if (pinActionFlags == NULL) {
tempFlags = 0;
pinActionFlags = &tempFlags;
}
result = This->DoRender(*pinActionFlags, *pinTimeStamp, pinOutputBusNumber, pinNumberFrames, *pioData);
}
}
}
break;
case kAudioUnitResetSelect:
{
CAMutex::Locker lock(This->GetMutex());
PARAM(AudioUnitScope, pinScope, 0, 2);
PARAM(AudioUnitElement, pinElement, 1, 2);
This->ResetRenderTime();
result = This->Reset(pinScope, pinElement);
}
break;
default:
result = ComponentBase::ComponentEntryDispatch(params, This);
break;
}
return result;
}
// Fast dispatch entry points -- these need to replicate all error-checking logic from above
OSStatus CMgr_AudioUnitBaseGetParameter( AUBase * This,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
float *outValue)
{
OSStatus result = AUBase::noErr;
try {
if (This == NULL || outValue == NULL) return kAudio_ParamError;
result = This->GetParameter(inID, inScope, inElement, *outValue);
}
COMPONENT_CATCH
return result;
}
OSStatus CMgr_AudioUnitBaseSetParameter( AUBase * This,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
float inValue,
UInt32 inBufferOffset)
{
OSStatus result = AUBase::noErr;
try {
if (This == NULL) return kAudio_ParamError;
result = This->SetParameter(inID, inScope, inElement, inValue, inBufferOffset);
}
COMPONENT_CATCH
return result;
}
OSStatus CMgr_AudioUnitBaseRender( AUBase * This,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
if (inTimeStamp == NULL || ioData == NULL) return kAudio_ParamError;
OSStatus result = AUBase::noErr;
AudioUnitRenderActionFlags tempFlags;
try {
if (ioActionFlags == NULL) {
tempFlags = 0;
ioActionFlags = &tempFlags;
}
result = This->DoRender(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, *ioData);
}
COMPONENT_CATCH
return result;
}

View File

@@ -0,0 +1,82 @@
/*
File: AUDispatch.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUDispatch_h__
#define __AUDispatch_h__
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AudioUnit.h>
#else
#include "AudioUnit.h"
#endif
#if !CA_USE_AUDIO_PLUGIN_ONLY
/*! @function AudioUnitBaseGetParameter */
OSStatus CMgr_AudioUnitBaseGetParameter( AUBase * This,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
float * outValue);
/*! @function AudioUnitBaseSetParameter */
OSStatus CMgr_AudioUnitBaseSetParameter( AUBase * This,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
float inValue,
UInt32 inBufferOffset);
/*! @function AudioUnitBaseRender */
OSStatus CMgr_AudioUnitBaseRender( AUBase * This,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData);
#endif
#endif // __AUDispatch_h__

View File

@@ -0,0 +1,151 @@
/*
File: AUInputElement.cpp
Abstract: AUInputElement.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUBase.h"
inline bool HasGoodBufferPointers(const AudioBufferList &abl, UInt32 nBytes)
{
const AudioBuffer *buf = abl.mBuffers;
for (UInt32 i = abl.mNumberBuffers; i--;++buf) {
if (buf->mData == NULL || buf->mDataByteSize < nBytes)
return false;
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUInputElement::AUInputElement
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AUInputElement::AUInputElement(AUBase *audioUnit) :
AUIOElement(audioUnit),
mInputType(kNoInput)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUInputElement::SetConnection
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void AUInputElement::SetConnection(const AudioUnitConnection &conn)
{
if (conn.sourceAudioUnit == 0) {
Disconnect();
return;
}
mInputType = kFromConnection;
mConnection = conn;
AllocateBuffer();
mConnInstanceStorage = NULL;
#if !CA_USE_AUDIO_PLUGIN_ONLY
mConnRenderProc = NULL;
UInt32 size = sizeof(AudioUnitRenderProc);
OSStatus result = AudioUnitGetProperty( conn.sourceAudioUnit,
kAudioUnitProperty_FastDispatch,
kAudioUnitScope_Global,
kAudioUnitRenderSelect,
&mConnRenderProc,
&size);
if (result == noErr)
mConnInstanceStorage = CMgr_GetComponentInstanceStorage (conn.sourceAudioUnit);
else
mConnRenderProc = NULL;
#endif
}
void AUInputElement::Disconnect()
{
mInputType = kNoInput;
mIOBuffer.Deallocate();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUInputElement::SetInputCallback
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void AUInputElement::SetInputCallback(AURenderCallback proc, void *refCon)
{
if (proc == NULL)
Disconnect();
else {
mInputType = kFromCallback;
mInputProc = proc;
mInputProcRefCon = refCon;
AllocateBuffer();
}
}
OSStatus AUInputElement::SetStreamFormat(const CAStreamBasicDescription &fmt)
{
OSStatus err = AUIOElement::SetStreamFormat(fmt);
if (err == AUBase::noErr)
AllocateBuffer();
return err;
}
OSStatus AUInputElement::PullInput( AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
AudioUnitElement inElement,
UInt32 nFrames)
{
if (!IsActive())
return kAudioUnitErr_NoConnection;
AudioBufferList *pullBuffer;
if (HasConnection() || !WillAllocateBuffer())
pullBuffer = &mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames);
else
pullBuffer = &mIOBuffer.PrepareBuffer(mStreamFormat, nFrames);
return PullInputWithBufferList (ioActionFlags, inTimeStamp, inElement, nFrames, pullBuffer);
}

View File

@@ -0,0 +1,119 @@
/*
File: AUInputElement.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUInput_h__
#define __AUInput_h__
#include "AUScopeElement.h"
#include "AUBuffer.h"
/*! @class AUInputElement */
class AUInputElement : public AUIOElement {
public:
/*! @ctor AUInputElement */
AUInputElement(AUBase *audioUnit);
/*! @dtor ~AUInputElement */
virtual ~AUInputElement() { }
// AUElement override
/*! @method SetStreamFormat */
virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
/*! @method NeedsBufferSpace */
virtual bool NeedsBufferSpace() const { return IsCallback(); }
/*! @method SetConnection */
void SetConnection(const AudioUnitConnection &conn);
/*! @method SetInputCallback */
void SetInputCallback(AURenderCallback proc, void *refCon);
/*! @method IsActive */
bool IsActive() const { return mInputType != kNoInput; }
/*! @method IsCallback */
bool IsCallback() const { return mInputType == kFromCallback; }
/*! @method HasConnection */
bool HasConnection() const { return mInputType == kFromConnection; }
/*! @method PullInput */
OSStatus PullInput( AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
AudioUnitElement inElement,
UInt32 inNumberFrames);
/*! @method PullInputWithBufferList */
OSStatus PullInputWithBufferList( AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
AudioUnitElement inElement,
UInt32 nFrames,
AudioBufferList * inBufferList);
protected:
/*! @method Disconnect */
void Disconnect();
enum EInputType { kNoInput, kFromConnection, kFromCallback };
/*! @var mInputType */
EInputType mInputType;
// if from callback:
/*! @var mInputProc */
AURenderCallback mInputProc;
/*! @var mInputProcRefCon */
void * mInputProcRefCon;
// if from connection:
/*! @var mConnection */
AudioUnitConnection mConnection;
#if !CA_USE_AUDIO_PLUGIN_ONLY
/*! @var mConnRenderProc */
AudioUnitRenderProc mConnRenderProc;
#endif
/*! @var mConnInstanceStorage */
void * mConnInstanceStorage; // for the input component
};
#endif // __AUInput_h__

View File

@@ -0,0 +1,62 @@
/*
File: AUOutputElement.cpp
Abstract: AUOutputElement.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUOutputElement.h"
#include "AUBase.h"
AUOutputElement::AUOutputElement(AUBase *audioUnit) :
AUIOElement(audioUnit)
{
AllocateBuffer();
}
OSStatus AUOutputElement::SetStreamFormat(const CAStreamBasicDescription &desc)
{
OSStatus result = AUIOElement::SetStreamFormat(desc); // inherited
if (result == AUBase::noErr)
AllocateBuffer();
return result;
}

View File

@@ -0,0 +1,66 @@
/*
File: AUOutputElement.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUOutput_h__
#define __AUOutput_h__
#include "AUScopeElement.h"
#include "AUBuffer.h"
/*! @class AUOutputElement */
class AUOutputElement : public AUIOElement {
public:
/*! @ctor AUOutputElement */
AUOutputElement(AUBase *audioUnit);
// AUElement override
/*! @method SetStreamFormat */
virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
/*! @method NeedsBufferSpace */
virtual bool NeedsBufferSpace() const { return true; }
};
#endif // __AUOutput_h__

View File

@@ -0,0 +1,669 @@
/*
File: AUPlugInDispatch.cpp
Abstract: AUPlugInDispatch.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUPlugInDispatch.h"
#include "CAXException.h"
#include "ComponentBase.h"
#include "AUBase.h"
#define ACPI ((AudioComponentPlugInInstance *)self)
#define AUI ((AUBase *)&ACPI->mInstanceStorage)
#define AUI_LOCK CAMutex::Locker auLock(AUI->GetMutex());
// ------------------------------------------------------------------------------------------------
static OSStatus AUMethodInitialize(void *self)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->DoInitialize();
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodUninitialize(void *self)
{
OSStatus result = noErr;
try {
AUI_LOCK
AUI->DoCleanup();
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodGetPropertyInfo(void *self, AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, UInt32 *outDataSize, Boolean *outWritable)
{
OSStatus result = noErr;
try {
UInt32 dataSize = 0; // 13517289 GetPropetyInfo was returning an uninitialized value when there is an error. This is a problem for auval.
Boolean writable = false;
AUI_LOCK
result = AUI->DispatchGetPropertyInfo(prop, scope, elem, dataSize, writable);
if (outDataSize != NULL)
*outDataSize = dataSize;
if (outWritable != NULL)
*outWritable = writable;
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodGetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void *outData, UInt32 *ioDataSize)
{
OSStatus result = noErr;
try {
UInt32 actualPropertySize, clientBufferSize;
Boolean writable;
char *tempBuffer;
void *destBuffer;
AUI_LOCK
if (ioDataSize == NULL) {
ca_debug_string("AudioUnitGetProperty: null size pointer");
result = kAudio_ParamError;
goto finishGetProperty;
}
if (outData == NULL) {
UInt32 dataSize;
result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, dataSize, writable);
*ioDataSize = dataSize;
goto finishGetProperty;
}
clientBufferSize = *ioDataSize;
if (clientBufferSize == 0)
{
ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry");
// $$$ or should we allow this as a shortcut for finding the size?
result = kAudio_ParamError;
goto finishGetProperty;
}
result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, actualPropertySize, writable);
if (result != noErr)
goto finishGetProperty;
if (clientBufferSize < actualPropertySize)
{
tempBuffer = new char[actualPropertySize];
destBuffer = tempBuffer;
} else {
tempBuffer = NULL;
destBuffer = outData;
}
result = AUI->DispatchGetProperty(inID, inScope, inElement, destBuffer);
if (result == noErr) {
if (clientBufferSize < actualPropertySize && tempBuffer != NULL)
{
memcpy(outData, tempBuffer, clientBufferSize);
delete[] tempBuffer;
// ioDataSize remains correct, the number of bytes we wrote
} else
*ioDataSize = actualPropertySize;
} else
*ioDataSize = 0;
}
COMPONENT_CATCH
finishGetProperty:
return result;
}
static OSStatus AUMethodSetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void *inData, UInt32 inDataSize)
{
OSStatus result = noErr;
try {
AUI_LOCK
if (inData && inDataSize)
result = AUI->DispatchSetProperty(inID, inScope, inElement, inData, inDataSize);
else {
if (inData == NULL && inDataSize == 0) {
result = AUI->DispatchRemovePropertyValue(inID, inScope, inElement);
} else {
if (inData == NULL) {
ca_debug_string("AudioUnitSetProperty: inData == NULL");
result = kAudio_ParamError;
goto finishSetProperty;
}
if (inDataSize == 0) {
ca_debug_string("AudioUnitSetProperty: inDataSize == 0");
result = kAudio_ParamError;
goto finishSetProperty;
}
}
}
}
COMPONENT_CATCH
finishSetProperty:
return result;
}
static OSStatus AUMethodAddPropertyListener(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void *userData)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->AddPropertyListener(prop, proc, userData);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodRemovePropertyListener(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->RemovePropertyListener(prop, proc, NULL, false);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodRemovePropertyListenerWithUserData(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void *userData)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->RemovePropertyListener(prop, proc, userData, true);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodAddRenderNotify(void *self, AURenderCallback proc, void *userData)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->SetRenderNotification(proc, userData);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodRemoveRenderNotify(void *self, AURenderCallback proc, void *userData)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->RemoveRenderNotification(proc, userData);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodGetParameter(void *self, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement elem, AudioUnitParameterValue *value)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = (value == NULL ? kAudio_ParamError : AUI->GetParameter(param, scope, elem, *value));
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodSetParameter(void *self, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement elem, AudioUnitParameterValue value, UInt32 bufferOffset)
{
OSStatus result = noErr;
try {
// this is a (potentially) realtime method; no lock
result = AUI->SetParameter(param, scope, elem, value, bufferOffset);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodScheduleParameters(void *self, const AudioUnitParameterEvent *events, UInt32 numEvents)
{
OSStatus result = noErr;
try {
// this is a (potentially) realtime method; no lock
result = AUI->ScheduleParameter(events, numEvents);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodRender(void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
OSStatus result = noErr;
#if !TARGET_OS_IPHONE
try {
#endif
// this is a processing method; no lock
AudioUnitRenderActionFlags tempFlags;
if (inTimeStamp == NULL || ioData == NULL)
result = kAudio_ParamError;
else {
if (ioActionFlags == NULL) {
tempFlags = 0;
ioActionFlags = &tempFlags;
}
result = AUI->DoRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberFrames, *ioData);
}
#if !TARGET_OS_IPHONE
}
COMPONENT_CATCH
#endif
return result;
}
static OSStatus AUMethodComplexRender(void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberOfPackets, UInt32 *outNumberOfPackets, AudioStreamPacketDescription *outPacketDescriptions, AudioBufferList *ioData, void *outMetadata, UInt32 *outMetadataByteSize)
{
OSStatus result = noErr;
#if !TARGET_OS_IPHONE
try {
#endif
// this is a processing method; no lock
AudioUnitRenderActionFlags tempFlags;
if (inTimeStamp == NULL || ioData == NULL)
result = kAudio_ParamError;
else {
if (ioActionFlags == NULL) {
tempFlags = 0;
ioActionFlags = &tempFlags;
}
result = AUI->ComplexRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberOfPackets, outNumberOfPackets, outPacketDescriptions, *ioData, outMetadata, outMetadataByteSize);
}
#if !TARGET_OS_IPHONE
}
COMPONENT_CATCH
#endif
return result;
}
static OSStatus AUMethodReset(void *self, AudioUnitScope scope, AudioUnitElement elem)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->Reset(scope, elem);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodProcess (void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData)
{
OSStatus result = noErr;
#if !TARGET_OS_IPHONE
try {
#endif
// this is a processing method; no lock
bool doParamCheck = true;
AudioUnitRenderActionFlags tempFlags;
if (ioActionFlags == NULL) {
tempFlags = 0;
ioActionFlags = &tempFlags;
} else {
if (*ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)
doParamCheck = false;
}
if (doParamCheck && (inTimeStamp == NULL || ioData == NULL))
result = kAudio_ParamError;
else {
result = AUI->DoProcess(*ioActionFlags, *inTimeStamp, inNumberFrames, *ioData);
}
#if !TARGET_OS_IPHONE
}
COMPONENT_CATCH
#endif
return result;
}
static OSStatus AUMethodProcessMultiple (void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, UInt32 inNumberInputBufferLists, const AudioBufferList **inInputBufferLists, UInt32 inNumberOutputBufferLists, AudioBufferList **ioOutputBufferLists)
{
OSStatus result = noErr;
#if !TARGET_OS_IPHONE
try {
#endif
// this is a processing method; no lock
bool doParamCheck = true;
AudioUnitRenderActionFlags tempFlags;
if (ioActionFlags == NULL) {
tempFlags = 0;
ioActionFlags = &tempFlags;
} else {
if (*ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)
doParamCheck = false;
}
if (doParamCheck && (inTimeStamp == NULL || inInputBufferLists == NULL || ioOutputBufferLists == NULL))
result = kAudio_ParamError;
else {
result = AUI->DoProcessMultiple(*ioActionFlags, *inTimeStamp, inNumberFrames, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
}
#if !TARGET_OS_IPHONE
}
COMPONENT_CATCH
#endif
return result;
}
// ------------------------------------------------------------------------------------------------
static OSStatus AUMethodStart(void *self)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->Start();
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodStop(void *self)
{
OSStatus result = noErr;
try {
AUI_LOCK
result = AUI->Stop();
}
COMPONENT_CATCH
return result;
}
// ------------------------------------------------------------------------------------------------
#if !CA_BASIC_AU_FEATURES
// I don't know what I'm doing here; conflicts with the multiple inheritence in MusicDeviceBase.
static OSStatus AUMethodMIDIEvent(void *self, UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame)
{
OSStatus result = noErr;
try {
// this is a potential render-time method; no lock
result = AUI->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodSysEx(void *self, const UInt8 *inData, UInt32 inLength)
{
OSStatus result = noErr;
try {
// this is a potential render-time method; no lock
result = AUI->SysEx(inData, inLength);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodStartNote(void *self, MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams)
{
OSStatus result = noErr;
try {
// this is a potential render-time method; no lock
if (inParams == NULL || outNoteInstanceID == NULL)
result = kAudio_ParamError;
else
result = AUI->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodStopNote(void *self, MusicDeviceGroupID inGroupID, NoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame)
{
OSStatus result = noErr;
try {
// this is a potential render-time method; no lock
result = AUI->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);
}
COMPONENT_CATCH
return result;
}
#if !TARGET_OS_IPHONE
static OSStatus AUMethodPrepareInstrument (void *self, MusicDeviceInstrumentID inInstrument)
{
OSStatus result = noErr;
try {
// this is a potential render-time method; no lock
result = AUI->PrepareInstrument(inInstrument);
}
COMPONENT_CATCH
return result;
}
static OSStatus AUMethodReleaseInstrument (void *self, MusicDeviceInstrumentID inInstrument)
{
OSStatus result = noErr;
try {
// this is a potential render-time method; no lock
result = AUI->ReleaseInstrument(inInstrument);
}
COMPONENT_CATCH
return result;
}
#endif // TARGET_OS_IPHONE
#endif // CA_BASIC_AU_FEATURES
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#pragma mark -
#pragma mark Lookup Methods
AudioComponentMethod AUBaseLookup::Lookup (SInt16 selector)
{
switch (selector) {
case kAudioUnitInitializeSelect: return (AudioComponentMethod)AUMethodInitialize;
case kAudioUnitUninitializeSelect: return (AudioComponentMethod)AUMethodUninitialize;
case kAudioUnitGetPropertyInfoSelect: return (AudioComponentMethod)AUMethodGetPropertyInfo;
case kAudioUnitGetPropertySelect: return (AudioComponentMethod)AUMethodGetProperty;
case kAudioUnitSetPropertySelect: return (AudioComponentMethod)AUMethodSetProperty;
case kAudioUnitAddPropertyListenerSelect:return (AudioComponentMethod)AUMethodAddPropertyListener;
case kAudioUnitRemovePropertyListenerSelect:
return (AudioComponentMethod)AUMethodRemovePropertyListener;
case kAudioUnitRemovePropertyListenerWithUserDataSelect:
return (AudioComponentMethod)AUMethodRemovePropertyListenerWithUserData;
case kAudioUnitAddRenderNotifySelect: return (AudioComponentMethod)AUMethodAddRenderNotify;
case kAudioUnitRemoveRenderNotifySelect:return (AudioComponentMethod)AUMethodRemoveRenderNotify;
case kAudioUnitGetParameterSelect: return (AudioComponentMethod)AUMethodGetParameter;
case kAudioUnitSetParameterSelect: return (AudioComponentMethod)AUMethodSetParameter;
case kAudioUnitScheduleParametersSelect:return (AudioComponentMethod)AUMethodScheduleParameters;
case kAudioUnitRenderSelect: return (AudioComponentMethod)AUMethodRender;
case kAudioUnitResetSelect: return (AudioComponentMethod)AUMethodReset;
default:
break;
}
return NULL;
}
AudioComponentMethod AUOutputLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
switch (selector) {
case kAudioOutputUnitStartSelect: return (AudioComponentMethod)AUMethodStart;
case kAudioOutputUnitStopSelect: return (AudioComponentMethod)AUMethodStop;
default:
break;
}
return NULL;
}
AudioComponentMethod AUComplexOutputLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
method = AUOutputLookup::Lookup(selector);
if (method) return method;
if (selector == kAudioUnitComplexRenderSelect)
return (AudioComponentMethod)AUMethodComplexRender;
return NULL;
}
AudioComponentMethod AUBaseProcessLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
if (selector == kAudioUnitProcessSelect)
return (AudioComponentMethod)AUMethodProcess;
return NULL;
}
AudioComponentMethod AUBaseProcessMultipleLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
if (selector == kAudioUnitProcessMultipleSelect)
return (AudioComponentMethod)AUMethodProcessMultiple;
return NULL;
}
AudioComponentMethod AUBaseProcessAndMultipleLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
method = AUBaseProcessMultipleLookup::Lookup(selector);
if (method) return method;
method = AUBaseProcessLookup::Lookup(selector);
if (method) return method;
return NULL;
}
#if !CA_BASIC_AU_FEATURES
inline AudioComponentMethod MIDI_Lookup (SInt16 selector)
{
switch (selector) {
case kMusicDeviceMIDIEventSelect: return (AudioComponentMethod)AUMethodMIDIEvent;
case kMusicDeviceSysExSelect: return (AudioComponentMethod)AUMethodSysEx;
default:
break;
}
return NULL;
}
AudioComponentMethod AUMIDILookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
return MIDI_Lookup(selector);
}
AudioComponentMethod AUMIDIProcessLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseProcessLookup::Lookup(selector);
if (method) return method;
return MIDI_Lookup(selector);
}
AudioComponentMethod AUMusicLookup::Lookup (SInt16 selector)
{
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
if (method) return method;
switch (selector) {
case kMusicDeviceStartNoteSelect: return (AudioComponentMethod)AUMethodStartNote;
case kMusicDeviceStopNoteSelect: return (AudioComponentMethod)AUMethodStopNote;
#if !TARGET_OS_IPHONE
case kMusicDevicePrepareInstrumentSelect: return (AudioComponentMethod)AUMethodPrepareInstrument;
case kMusicDeviceReleaseInstrumentSelect: return (AudioComponentMethod)AUMethodReleaseInstrument;
#endif
default:
break;
}
return MIDI_Lookup (selector);
}
AudioComponentMethod AUAuxBaseLookup::Lookup (SInt16 selector)
{
switch (selector) {
case kAudioUnitGetPropertyInfoSelect: return (AudioComponentMethod)AUMethodGetPropertyInfo;
case kAudioUnitGetPropertySelect: return (AudioComponentMethod)AUMethodGetProperty;
case kAudioUnitSetPropertySelect: return (AudioComponentMethod)AUMethodSetProperty;
case kAudioUnitGetParameterSelect: return (AudioComponentMethod)AUMethodGetParameter;
case kAudioUnitSetParameterSelect: return (AudioComponentMethod)AUMethodSetParameter;
default:
break;
}
return NULL;
}
#endif

View File

@@ -0,0 +1,144 @@
/*
File: AUPlugInDispatch.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUPlugInBase_h__
#define __AUPlugInBase_h__
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AudioComponent.h>
#if !CA_BASIC_AU_FEATURES
#include <AudioUnit/MusicDevice.h>
#endif
#else
#include "AudioComponent.h"
#include "MusicDevice.h"
#endif
#include "ComponentBase.h"
struct AUBaseLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUBaseFactory : public APFactory<AUBaseLookup, Implementor>
{
};
struct AUOutputLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUOutputBaseFactory : public APFactory<AUOutputLookup, Implementor>
{
};
struct AUComplexOutputLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUOutputComplexBaseFactory : public APFactory<AUComplexOutputLookup, Implementor>
{
};
struct AUBaseProcessLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUBaseProcessFactory : public APFactory<AUBaseProcessLookup, Implementor>
{
};
struct AUBaseProcessMultipleLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUBaseProcessMultipleFactory : public APFactory<AUBaseProcessMultipleLookup, Implementor>
{
};
struct AUBaseProcessAndMultipleLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUBaseProcessAndMultipleFactory : public APFactory<AUBaseProcessAndMultipleLookup, Implementor>
{
};
#if !CA_BASIC_AU_FEATURES
struct AUMIDILookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUMIDIEffectFactory : public APFactory<AUMIDILookup, Implementor>
{
};
struct AUMIDIProcessLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUMIDIProcessFactory : public APFactory<AUMIDIProcessLookup, Implementor>
{
};
struct AUMusicLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUMusicDeviceFactory : public APFactory<AUMusicLookup, Implementor>
{
};
struct AUAuxBaseLookup {
static AudioComponentMethod Lookup (SInt16 selector);
};
template <class Implementor>
class AUAuxBaseFactory : public APFactory<AUAuxBaseLookup, Implementor>
{
};
#endif // CA_BASIC_AU_FEATURES
#endif // __AUPlugInBase_h__

View File

@@ -0,0 +1,140 @@
/*
File: AUResources.r
Abstract: AUResources.r
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUResources.r
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* sample macro definitions -- all of these symbols must be defined
#define RES_ID kHALOutputResID
#define COMP_TYPE kAudioUnitComponentType
#define COMP_SUBTYPE kAudioUnitOutputSubType
#define COMP_MANUF kAudioUnitAudioHardwareOutputSubSubType
#define VERSION 0x00010000
#define NAME "AudioHALOutput"
#define DESCRIPTION "Audio hardware output AudioUnit"
#define ENTRY_POINT "AUHALEntry"
*/
#define UseExtendedThingResource 1
#include <CoreServices/CoreServices.r>
// this is a define used to indicate that a component has no static data that would mean
// that no more than one instance could be open at a time - never been true for AUs
#ifndef cmpThreadSafeOnMac
#define cmpThreadSafeOnMac 0x10000000
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
resource 'STR ' (RES_ID, purgeable) {
NAME
};
resource 'STR ' (RES_ID + 1, purgeable) {
DESCRIPTION
};
resource 'dlle' (RES_ID) {
ENTRY_POINT
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
resource 'thng' (RES_ID, NAME) {
COMP_TYPE,
COMP_SUBTYPE,
COMP_MANUF,
0, 0, 0, 0, // no 68K
'STR ', RES_ID,
'STR ', RES_ID + 1,
0, 0, /* icon */
VERSION,
componentHasMultiplePlatforms | componentDoAutoVersion,
0,
{
#if defined(ppc_YES)
cmpThreadSafeOnMac,
'dlle', RES_ID, platformPowerPCNativeEntryPoint
#define NeedLeadingComma 1
#endif
#if defined(ppc64_YES)
#if defined(NeedLeadingComma)
,
#endif
cmpThreadSafeOnMac,
'dlle', RES_ID, platformPowerPC64NativeEntryPoint
#define NeedLeadingComma 1
#endif
#if defined(i386_YES)
#if defined(NeedLeadingComma)
,
#endif
cmpThreadSafeOnMac,
'dlle', RES_ID, platformIA32NativeEntryPoint
#define NeedLeadingComma 1
#endif
#if defined(x86_64_YES)
#if defined(NeedLeadingComma)
,
#endif
cmpThreadSafeOnMac,
'dlle', RES_ID, 8
#define NeedLeadingComma 1
#endif
}
};
#undef RES_ID
#undef COMP_TYPE
#undef COMP_SUBTYPE
#undef COMP_MANUF
#undef VERSION
#undef NAME
#undef DESCRIPTION
#undef ENTRY_POINT
#undef NeedLeadingComma

View File

@@ -0,0 +1,565 @@
/*
File: AUScopeElement.cpp
Abstract: AUScopeElement.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUScopeElement.h"
#include "AUBase.h"
//_____________________________________________________________________________
//
// By default, parameterIDs may be arbitrarily spaced, and an STL map
// will be used for access. Calling UseIndexedParameters() will
// instead use an STL vector for faster indexed access.
// This assumes the paramIDs are numbered 0.....inNumberOfParameters-1
// Call this before defining/adding any parameters with SetParameter()
//
void AUElement::UseIndexedParameters(int inNumberOfParameters)
{
mIndexedParameters.resize (inNumberOfParameters);
mUseIndexedParameters = true;
}
//_____________________________________________________________________________
//
// Helper method.
// returns the ParameterMapEvent object associated with the paramID
//
inline ParameterMapEvent& AUElement::GetParamEvent(AudioUnitParameterID paramID)
{
ParameterMapEvent *event;
if(mUseIndexedParameters)
{
if(paramID >= mIndexedParameters.size() )
COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
event = &mIndexedParameters[paramID];
}
else
{
ParameterMap::iterator i = mParameters.find(paramID);
if (i == mParameters.end())
COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
event = &(*i).second;
}
return *event;
}
//_____________________________________________________________________________
//
// Helper method.
// returns whether the specified paramID is known to the element
//
bool AUElement::HasParameterID (AudioUnitParameterID paramID) const
{
if(mUseIndexedParameters)
{
if(paramID >= mIndexedParameters.size() )
return false;
return true;
}
ParameterMap::const_iterator i = mParameters.find(paramID);
if (i == mParameters.end())
return false;
return true;
}
//_____________________________________________________________________________
//
// caller assumes that this is actually an immediate parameter
//
AudioUnitParameterValue AUElement::GetParameter(AudioUnitParameterID paramID)
{
ParameterMapEvent &event = GetParamEvent(paramID);
return event.GetValue();
}
//_____________________________________________________________________________
//
void AUElement::GetRampSliceStartEnd( AudioUnitParameterID paramID,
AudioUnitParameterValue & outStartValue,
AudioUnitParameterValue & outEndValue,
AudioUnitParameterValue & outValuePerFrameDelta )
{
ParameterMapEvent &event = GetParamEvent(paramID);
// works even if the value is constant (immediate parameter value)
event.GetRampSliceStartEnd(outStartValue, outEndValue, outValuePerFrameDelta );
}
//_____________________________________________________________________________
//
AudioUnitParameterValue AUElement::GetEndValue( AudioUnitParameterID paramID)
{
ParameterMapEvent &event = GetParamEvent(paramID);
// works even if the value is constant (immediate parameter value)
return event.GetEndValue();
}
//_____________________________________________________________________________
//
void AUElement::SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue inValue, bool okWhenInitialized)
{
if(mUseIndexedParameters)
{
ParameterMapEvent &event = GetParamEvent(paramID);
event.SetValue(inValue);
}
else
{
ParameterMap::iterator i = mParameters.find(paramID);
if (i == mParameters.end())
{
if (mAudioUnit->IsInitialized() && !okWhenInitialized) {
// The AU should not be creating new parameters once initialized.
// If a client tries to set an undefined parameter, we could throw as follows,
// but this might cause a regression. So it is better to just fail silently.
// COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
#if DEBUG
fprintf(stderr, "WARNING: %s SetParameter for undefined param ID %d while initialized. Ignoring..\n",
mAudioUnit->GetLoggingString(), (int)paramID);
#endif
} else {
// create new entry in map for the paramID (only happens first time)
ParameterMapEvent event(inValue);
mParameters[paramID] = event;
}
}
else
{
// paramID already exists in map so simply change its value
ParameterMapEvent &event = (*i).second;
event.SetValue(inValue);
}
}
}
//_____________________________________________________________________________
//
void AUElement::SetScheduledEvent( AudioUnitParameterID paramID,
const AudioUnitParameterEvent &inEvent,
UInt32 inSliceOffsetInBuffer,
UInt32 inSliceDurationFrames,
bool okWhenInitialized )
{
if(mUseIndexedParameters)
{
ParameterMapEvent &event = GetParamEvent(paramID);
event.SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
}
else
{
ParameterMap::iterator i = mParameters.find(paramID);
if (i == mParameters.end())
{
if (mAudioUnit->IsInitialized() && !okWhenInitialized) {
// The AU should not be creating new parameters once initialized.
// If a client tries to set an undefined parameter, we could throw as follows,
// but this might cause a regression. So it is better to just fail silently.
// COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
#if DEBUG
fprintf(stderr, "WARNING: %s SetScheduledEvent for undefined param ID %d while initialized. Ignoring..\n",
mAudioUnit->GetLoggingString(), (int)paramID);
#endif
} else {
// create new entry in map for the paramID (only happens first time)
ParameterMapEvent event(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames);
mParameters[paramID] = event;
}
}
else
{
// paramID already exists in map so simply change its value
ParameterMapEvent &event = (*i).second;
event.SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
}
}
}
//_____________________________________________________________________________
//
void AUElement::GetParameterList(AudioUnitParameterID *outList)
{
if(mUseIndexedParameters)
{
UInt32 nparams = static_cast<UInt32>(mIndexedParameters.size());
for (UInt32 i = 0; i < nparams; i++ )
*outList++ = (AudioUnitParameterID)i;
}
else
{
for (ParameterMap::iterator i = mParameters.begin(); i != mParameters.end(); ++i)
*outList++ = (*i).first;
}
}
//_____________________________________________________________________________
//
void AUElement::SaveState(CFMutableDataRef data)
{
if(mUseIndexedParameters)
{
UInt32 nparams = static_cast<UInt32>(mIndexedParameters.size());
UInt32 theData = CFSwapInt32HostToBig(nparams);
CFDataAppendBytes(data, (UInt8 *)&theData, sizeof(nparams));
for (UInt32 i = 0; i < nparams; i++)
{
struct {
UInt32 paramID;
//CFSwappedFloat32 value; crashes gcc3 PFE
UInt32 value; // really a big-endian float
} entry;
entry.paramID = CFSwapInt32HostToBig(i);
AudioUnitParameterValue v = mIndexedParameters[i].GetValue();
entry.value = CFSwapInt32HostToBig(*(UInt32 *)&v );
CFDataAppendBytes(data, (UInt8 *)&entry, sizeof(entry));
}
}
else
{
UInt32 nparams = CFSwapInt32HostToBig(static_cast<uint32_t>(mParameters.size()));
CFDataAppendBytes(data, (UInt8 *)&nparams, sizeof(nparams));
for (ParameterMap::iterator i = mParameters.begin(); i != mParameters.end(); ++i) {
struct {
UInt32 paramID;
//CFSwappedFloat32 value; crashes gcc3 PFE
UInt32 value; // really a big-endian float
} entry;
entry.paramID = CFSwapInt32HostToBig((*i).first);
AudioUnitParameterValue v = (*i).second.GetValue();
entry.value = CFSwapInt32HostToBig(*(UInt32 *)&v );
CFDataAppendBytes(data, (UInt8 *)&entry, sizeof(entry));
}
}
}
//_____________________________________________________________________________
//
const UInt8 * AUElement::RestoreState(const UInt8 *state)
{
union FloatInt32 { UInt32 i; AudioUnitParameterValue f; };
const UInt8 *p = state;
UInt32 nparams = CFSwapInt32BigToHost(*(UInt32 *)p);
p += sizeof(UInt32);
for (UInt32 i = 0; i < nparams; ++i) {
struct {
AudioUnitParameterID paramID;
AudioUnitParameterValue value;
} entry;
entry.paramID = CFSwapInt32BigToHost(*(UInt32 *)p);
p += sizeof(UInt32);
FloatInt32 temp;
temp.i = CFSwapInt32BigToHost(*(UInt32 *)p);
entry.value = temp.f;
p += sizeof(AudioUnitParameterValue);
SetParameter(entry.paramID, entry.value);
}
return p;
}
//_____________________________________________________________________________
//
void AUElement::SetName (CFStringRef inName)
{
if (mElementName) CFRelease (mElementName);
mElementName = inName;
if (mElementName) CFRetain (mElementName);
}
//_____________________________________________________________________________
//
AUIOElement::AUIOElement(AUBase *audioUnit) :
AUElement(audioUnit),
mWillAllocate (true)
{
mStreamFormat.SetAUCanonical(2, // stereo
audioUnit->AudioUnitAPIVersion() == 1);
// interleaved if API version 1, deinterleaved if version 2
mStreamFormat.mSampleRate = kAUDefaultSampleRate;
}
//_____________________________________________________________________________
//
OSStatus AUIOElement::SetStreamFormat(const CAStreamBasicDescription &desc)
{
mStreamFormat = desc;
return AUBase::noErr;
}
//_____________________________________________________________________________
// inFramesToAllocate == 0 implies the AudioUnit's max-frames-per-slice will be used
void AUIOElement::AllocateBuffer(UInt32 inFramesToAllocate)
{
if (GetAudioUnit()->HasBegunInitializing())
{
UInt32 framesToAllocate = inFramesToAllocate > 0 ? inFramesToAllocate : GetAudioUnit()->GetMaxFramesPerSlice();
// printf ("will allocate: %d\n", (int)((mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0));
mIOBuffer.Allocate(mStreamFormat, (mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0);
}
}
//_____________________________________________________________________________
//
void AUIOElement::DeallocateBuffer()
{
mIOBuffer.Deallocate();
}
//_____________________________________________________________________________
//
// AudioChannelLayout support
// outLayoutTagsPtr WILL be NULL if called to find out how many
// layouts that Audio Unit will report
// return 0 (ie. NO channel layouts) if the AU doesn't require channel layout knowledge
UInt32 AUIOElement::GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr)
{
return 0;
}
// As the AudioChannelLayout can be a variable length structure
// (though in most cases it won't be!!!)
// The size of the ACL is always returned by the method
// if outMapPtr is NOT-NULL, then AU should copy into this pointer (outMapPtr) the current ACL that it has in use.
// the AU should also return whether the property is writable (that is the client can provide any arbitrary ACL that the audio unit will then honour)
// or if the property is read only - which is the generally preferred mode.
// If the AU doesn't require an AudioChannelLayout, then just return 0.
UInt32 AUIOElement::GetAudioChannelLayout (AudioChannelLayout *outMapPtr,
Boolean &outWritable)
{
return 0;
}
// the incoming channel map will be at least as big as a basic AudioChannelLayout
// but its contents will determine its actual size
// Subclass should overide if channel map is writable
OSStatus AUIOElement::SetAudioChannelLayout (const AudioChannelLayout &inData)
{
return kAudioUnitErr_InvalidProperty;
}
// Some units support optional usage of channel maps - typically converter units
// that can do channel remapping between different maps. In that optional case
// the user should be able to remove a channel map if that is possible.
// Typically this is NOT the case (e.g., the 3DMixer even in the stereo case
// needs to know if it is rendering to speakers or headphones)
OSStatus AUIOElement::RemoveAudioChannelLayout ()
{
return kAudioUnitErr_InvalidPropertyValue;
}
//_____________________________________________________________________________
//
AUScope::~AUScope()
{
for (ElementVector::iterator it = mElements.begin(); it != mElements.end(); ++it)
delete *it;
}
//_____________________________________________________________________________
//
void AUScope::SetNumberOfElements(UInt32 numElements)
{
if (mDelegate)
return mDelegate->SetNumberOfElements(numElements);
if (numElements > mElements.size()) {
mElements.reserve(numElements);
while (numElements > mElements.size()) {
AUElement *elem = mCreator->CreateElement(GetScope(), static_cast<UInt32>(mElements.size()));
mElements.push_back(elem);
}
} else
while (numElements < mElements.size()) {
AUElement *elem = mElements.back();
mElements.pop_back();
delete elem;
}
}
//_____________________________________________________________________________
//
bool AUScope::HasElementWithName () const
{
for (UInt32 i = 0; i < GetNumberOfElements(); ++i) {
AUElement * el = const_cast<AUScope*>(this)->GetElement (i);
if (el && el->HasName()) {
return true;
}
}
return false;
}
//_____________________________________________________________________________
//
void AUScope::AddElementNamesToDict (CFMutableDictionaryRef & inNameDict)
{
if (HasElementWithName())
{
static char string[32];
CFMutableDictionaryRef elementDict = CFDictionaryCreateMutable (NULL, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef str;
for (UInt32 i = 0; i < GetNumberOfElements(); ++i) {
AUElement * el = GetElement (i);
if (el && el->HasName()) {
snprintf (string, sizeof(string), "%d", int(i));
str = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
CFDictionarySetValue (elementDict, str, el->GetName());
CFRelease (str);
}
}
snprintf (string, sizeof(string), "%d", int(mScope));
str = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
CFDictionarySetValue (inNameDict, str, elementDict);
CFRelease (str);
CFRelease (elementDict);
}
}
//_____________________________________________________________________________
//
bool AUScope::RestoreElementNames (CFDictionaryRef& inNameDict)
{
static char string[32];
//first we have to see if we have enough elements
bool didAddElements = false;
unsigned int maxElNum = GetNumberOfElements();
int dictSize = static_cast<int>(CFDictionaryGetCount(inNameDict));
CFStringRef * keys = (CFStringRef*)CA_malloc (dictSize * sizeof (CFStringRef));
CFDictionaryGetKeysAndValues (inNameDict, reinterpret_cast<const void**>(keys), NULL);
for (int i = 0; i < dictSize; i++)
{
unsigned int intKey = 0;
CFStringGetCString (keys[i], string, 32, kCFStringEncodingASCII);
int result = sscanf (string, "%u", &intKey);
// check if sscanf succeeded and element index is less than max elements.
if (result && UInt32(intKey) < maxElNum)
{
CFStringRef elName = reinterpret_cast<CFStringRef>(CFDictionaryGetValue (inNameDict, keys[i]));
AUElement* element = GetElement (intKey);
if (element)
element->SetName (elName);
}
}
free (keys);
return didAddElements;
}
void AUScope::SaveState(CFMutableDataRef data)
{
AudioUnitElement nElems = GetNumberOfElements();
for (AudioUnitElement ielem = 0; ielem < nElems; ++ielem) {
AUElement *element = GetElement(ielem);
UInt32 nparams = element->GetNumberOfParameters();
if (nparams > 0) {
struct {
UInt32 scope;
UInt32 element;
} hdr;
hdr.scope = CFSwapInt32HostToBig(GetScope());
hdr.element = CFSwapInt32HostToBig(ielem);
CFDataAppendBytes(data, (UInt8 *)&hdr, sizeof(hdr));
element->SaveState(data);
}
}
}
const UInt8 * AUScope::RestoreState(const UInt8 *state)
{
const UInt8 *p = state;
UInt32 elementIdx = CFSwapInt32BigToHost(*(UInt32 *)p); p += sizeof(UInt32);
AUElement *element = GetElement(elementIdx);
if (!element) {
struct {
AudioUnitParameterID paramID;
AudioUnitParameterValue value;
} entry;
UInt32 nparams = CFSwapInt32BigToHost(*(UInt32 *)p);
p += sizeof(UInt32);
p += nparams * sizeof(entry);
} else
p = element->RestoreState(p);
return p;
}

View File

@@ -0,0 +1,553 @@
/*
File: AUScopeElement.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUScopeElement_h__
#define __AUScopeElement_h__
#include <map>
#include <vector>
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AudioUnit.h>
#else
#include <AudioUnit.h>
#endif
#include "ComponentBase.h"
#include "AUBuffer.h"
class AUBase;
// ____________________________________________________________________________
//
// represents a parameter's value (either constant or ramped)
/*! @class ParameterMapEvent */
class ParameterMapEvent
{
public:
/*! @ctor ParameterMapEvent */
ParameterMapEvent()
: mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(0.0f), mValue2(0.0f), mSliceDurationFrames(0)
{}
/*! @ctor ParameterMapEvent */
ParameterMapEvent(AudioUnitParameterValue inValue)
: mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(inValue), mValue2(inValue), mSliceDurationFrames(0)
{}
// constructor for scheduled event
/*! @ctor ParameterMapEvent */
ParameterMapEvent( const AudioUnitParameterEvent &inEvent,
UInt32 inSliceOffsetInBuffer,
UInt32 inSliceDurationFrames )
{
SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
};
/*! @method SetScheduledEvent */
void SetScheduledEvent( const AudioUnitParameterEvent &inEvent,
UInt32 inSliceOffsetInBuffer,
UInt32 inSliceDurationFrames )
{
mEventType = inEvent.eventType;
mSliceDurationFrames = inSliceDurationFrames;
if(mEventType == kParameterEvent_Immediate )
{
// constant immediate value for the whole slice
mValue1 = inEvent.eventValues.immediate.value;
mValue2 = mValue1;
mDurationInFrames = inSliceDurationFrames;
mBufferOffset = 0;
}
else
{
mDurationInFrames = inEvent.eventValues.ramp.durationInFrames;
mBufferOffset = inEvent.eventValues.ramp.startBufferOffset - inSliceOffsetInBuffer; // shift over for this slice
mValue1 = inEvent.eventValues.ramp.startValue;
mValue2 = inEvent.eventValues.ramp.endValue;
}
};
/*! @method GetEventType */
AUParameterEventType GetEventType() const {return mEventType;};
/*! @method GetValue */
AudioUnitParameterValue GetValue() const {return mValue1;}; // only valid if immediate event type
/*! @method GetEndValue */
AudioUnitParameterValue GetEndValue() const {return mValue2;}; // only valid if immediate event type
/*! @method SetValue */
void SetValue(AudioUnitParameterValue inValue)
{
mEventType = kParameterEvent_Immediate;
mValue1 = inValue;
mValue2 = inValue;
}
// interpolates the start and end values corresponding to the current processing slice
// most ramp parameter implementations will want to use this method
// the start value will correspond to the start of the slice
// the end value will correspond to the end of the slice
/*! @method GetRampSliceStartEnd */
void GetRampSliceStartEnd( AudioUnitParameterValue & outStartValue,
AudioUnitParameterValue & outEndValue,
AudioUnitParameterValue & outValuePerFrameDelta )
{
if (mEventType == kParameterEvent_Ramped) {
outValuePerFrameDelta = (mValue2 - mValue1) / mDurationInFrames;
outStartValue = mValue1 + outValuePerFrameDelta * (-mBufferOffset); // corresponds to frame 0 of this slice
outEndValue = outStartValue + outValuePerFrameDelta * mSliceDurationFrames;
} else {
outValuePerFrameDelta = 0;
outStartValue = outEndValue = mValue1;
}
};
// Some ramp parameter implementations will want to interpret the ramp using their
// own interpolation method (perhaps non-linear)
// This method gives the raw ramp information, relative to this processing slice
// for the client to interpret as desired
/*! @method GetRampInfo */
void GetRampInfo( SInt32 & outBufferOffset,
UInt32 & outDurationInFrames,
AudioUnitParameterValue & outStartValue,
AudioUnitParameterValue & outEndValue )
{
outBufferOffset = mBufferOffset;
outDurationInFrames = mDurationInFrames;
outStartValue = mValue1;
outEndValue = mValue2;
};
#if DEBUG
void Print()
{
printf("ParameterEvent @ %p\n", this);
printf(" mEventType = %d\n", (int)mEventType);
printf(" mBufferOffset = %d\n", (int)mBufferOffset);
printf(" mDurationInFrames = %d\n", (int)mDurationInFrames);
printf(" mSliceDurationFrames = %d\n", (int)mSliceDurationFrames);
printf(" mValue1 = %.5f\n", mValue1);
printf(" mValue2 = %.5f\n", mValue2);
}
#endif
private:
AUParameterEventType mEventType;
SInt32 mBufferOffset; // ramp start offset relative to start of this slice (may be negative)
UInt32 mDurationInFrames; // total duration of ramp parameter
AudioUnitParameterValue mValue1; // value if immediate : startValue if ramp
AudioUnitParameterValue mValue2; // endValue (only used for ramp)
UInt32 mSliceDurationFrames; // duration of this processing slice
};
// ____________________________________________________________________________
//
class AUIOElement;
/*! @class AUElement */
class AUElement {
public:
/*! @ctor AUElement */
AUElement(AUBase *audioUnit) : mAudioUnit(audioUnit),
mUseIndexedParameters(false), mElementName(0) { }
/*! @dtor ~AUElement */
virtual ~AUElement() { if (mElementName) CFRelease (mElementName); }
/*! @method GetNumberOfParameters */
virtual UInt32 GetNumberOfParameters()
{
if(mUseIndexedParameters) return static_cast<UInt32>(mIndexedParameters.size()); else return static_cast<UInt32>(mParameters.size());
}
/*! @method GetParameterList */
virtual void GetParameterList(AudioUnitParameterID *outList);
/*! @method HasParameterID */
bool HasParameterID (AudioUnitParameterID paramID) const;
/*! @method GetParameter */
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID);
/*! @method SetParameter */
void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value, bool okWhenInitialized = false);
// Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted.
// interpolates the start and end values corresponding to the current processing slice
// most ramp parameter implementations will want to use this method
/*! @method GetRampSliceStartEnd */
void GetRampSliceStartEnd( AudioUnitParameterID paramID,
AudioUnitParameterValue & outStartValue,
AudioUnitParameterValue & outEndValue,
AudioUnitParameterValue & outValuePerFrameDelta );
/*! @method GetEndValue */
AudioUnitParameterValue GetEndValue( AudioUnitParameterID paramID);
/*! @method SetRampParameter */
void SetScheduledEvent( AudioUnitParameterID paramID,
const AudioUnitParameterEvent &inEvent,
UInt32 inSliceOffsetInBuffer,
UInt32 inSliceDurationFrames,
bool okWhenInitialized = false );
// Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted.
/*! @method GetAudioUnit */
AUBase * GetAudioUnit() const { return mAudioUnit; };
/*! @method SaveState */
void SaveState(CFMutableDataRef data);
/*! @method RestoreState */
const UInt8 * RestoreState(const UInt8 *state);
/*! @method GetName */
CFStringRef GetName () const { return mElementName; }
/*! @method SetName */
void SetName (CFStringRef inName);
/*! @method HasName */
bool HasName () const { return mElementName != 0; }
/*! @method UseIndexedParameters */
virtual void UseIndexedParameters(int inNumberOfParameters);
/*! @method AsIOElement*/
virtual AUIOElement* AsIOElement () { return NULL; }
protected:
inline ParameterMapEvent& GetParamEvent(AudioUnitParameterID paramID);
private:
typedef std::map<AudioUnitParameterID, ParameterMapEvent, std::less<AudioUnitParameterID> > ParameterMap;
/*! @var mAudioUnit */
AUBase * mAudioUnit;
/*! @var mParameters */
ParameterMap mParameters;
/*! @var mUseIndexedParameters */
bool mUseIndexedParameters;
/*! @var mIndexedParameters */
std::vector<ParameterMapEvent> mIndexedParameters;
/*! @var mElementName */
CFStringRef mElementName;
};
// ____________________________________________________________________________
//
/*! @class AUIOElement */
class AUIOElement : public AUElement {
public:
/*! @ctor AUIOElement */
AUIOElement(AUBase *audioUnit);
/*! @method GetStreamFormat */
const CAStreamBasicDescription &GetStreamFormat() const { return mStreamFormat; }
/*! @method SetStreamFormat */
virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
/*! @method AllocateBuffer */
virtual void AllocateBuffer(UInt32 inFramesToAllocate = 0);
/*! @method DeallocateBuffer */
void DeallocateBuffer();
/*! @method NeedsBufferSpace */
virtual bool NeedsBufferSpace() const = 0;
/*! @method SetWillAllocateBuffer */
void SetWillAllocateBuffer(bool inFlag) {
mWillAllocate = inFlag;
}
/*! @method WillAllocateBuffer */
bool WillAllocateBuffer() const {
return mWillAllocate;
}
/*! @method UseExternalBuffer */
void UseExternalBuffer(const AudioUnitExternalBuffer &buf) {
mIOBuffer.UseExternalBuffer(mStreamFormat, buf);
}
/*! @method PrepareBuffer */
AudioBufferList & PrepareBuffer(UInt32 nFrames) {
if (mWillAllocate)
return mIOBuffer.PrepareBuffer(mStreamFormat, nFrames);
throw OSStatus(kAudioUnitErr_InvalidPropertyValue);
}
/*! @method PrepareNullBuffer */
AudioBufferList & PrepareNullBuffer(UInt32 nFrames) {
return mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames);
}
/*! @method SetBufferList */
AudioBufferList & SetBufferList(AudioBufferList &abl) { return mIOBuffer.SetBufferList(abl); }
/*! @method SetBuffer */
void SetBuffer(UInt32 index, AudioBuffer &ab) { mIOBuffer.SetBuffer(index, ab); }
/*! @method InvalidateBufferList */
void InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); }
/*! @method GetBufferList */
AudioBufferList & GetBufferList() const { return mIOBuffer.GetBufferList(); }
/*! @method GetChannelData */
AudioUnitSampleType * GetChannelData(int ch) const {
if (mStreamFormat.IsInterleaved())
return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
else
return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
}
Float32 * GetFloat32ChannelData(int ch) const {
if (mStreamFormat.IsInterleaved())
return static_cast<Float32 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
else
return static_cast<Float32 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
}
SInt32 * GetSInt32ChannelData(int ch) const {
if (mStreamFormat.IsInterleaved())
return static_cast<SInt32 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
else
return static_cast<SInt32 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
}
SInt16 * GetInt16ChannelData(int ch) const {
if (mStreamFormat.IsInterleaved())
return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
else
return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
}
/*! @method CopyBufferListTo */
void CopyBufferListTo(AudioBufferList &abl) const {
mIOBuffer.CopyBufferListTo(abl);
}
/*! @method CopyBufferContentsTo */
void CopyBufferContentsTo(AudioBufferList &abl) const {
mIOBuffer.CopyBufferContentsTo(abl);
}
/* UInt32 BytesToFrames(UInt32 nBytes) { return nBytes / mStreamFormat.mBytesPerFrame; }
UInt32 BytesToFrames(AudioBufferList &abl) {
return BytesToFrames(abl.mBuffers[0].mDataByteSize);
}
UInt32 FramesToBytes(UInt32 nFrames) { return nFrames * mStreamFormat.mBytesPerFrame; }*/
/*! @method IsInterleaved */
bool IsInterleaved() const { return mStreamFormat.IsInterleaved(); }
/*! @method NumberChannels */
UInt32 NumberChannels() const { return mStreamFormat.NumberChannels(); }
/*! @method NumberInterleavedChannels */
UInt32 NumberInterleavedChannels() const { return mStreamFormat.NumberInterleavedChannels(); }
/*! @method GetChannelMapTags */
virtual UInt32 GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr);
/*! @method GetAudioChannelLayout */
virtual UInt32 GetAudioChannelLayout (AudioChannelLayout *outMapPtr, Boolean &outWritable);
/*! @method SetAudioChannelLayout */
virtual OSStatus SetAudioChannelLayout (const AudioChannelLayout &inData);
/*! @method RemoveAudioChannelLayout */
virtual OSStatus RemoveAudioChannelLayout ();
/*! @method AsIOElement*/
virtual AUIOElement* AsIOElement () { return this; }
protected:
/*! @var mStreamFormat */
CAStreamBasicDescription mStreamFormat;
/*! @var mIOBuffer */
AUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed
// for output: output cache, usually allocated early on
/*! @var mWillAllocate */
bool mWillAllocate;
};
// ____________________________________________________________________________
//
// AUScopeDelegates are a way to get virtual scopes.
/*! @class AUScopeDelegate */
class AUScopeDelegate {
public:
/*! @ctor AUScopeDelegate */
AUScopeDelegate() : mCreator(NULL), mScope(0) { }
/*! @dtor ~AUScopeDelegate */
virtual ~AUScopeDelegate() {}
/*! @method Initialize */
void Initialize( AUBase *creator,
AudioUnitScope scope,
UInt32 numElements)
{
mCreator = creator;
mScope = scope;
SetNumberOfElements(numElements);
}
/*! @method SetNumberOfElements */
virtual void SetNumberOfElements(UInt32 numElements) = 0;
/*! @method GetNumberOfElements */
virtual UInt32 GetNumberOfElements() = 0;
/*! @method GetElement */
virtual AUElement * GetElement(UInt32 elementIndex) = 0;
AUBase * GetCreator() const { return mCreator; }
AudioUnitScope GetScope() const { return mScope; }
private:
/*! @var mCreator */
AUBase * mCreator;
/*! @var mScope */
AudioUnitScope mScope;
};
// ____________________________________________________________________________
//
/*! @class AUScope */
class AUScope {
public:
/*! @ctor AUScope */
AUScope() : mCreator(NULL), mScope(0), mDelegate(0) { }
/*! @dtor ~AUScope */
~AUScope();
/*! @method Initialize */
void Initialize(AUBase *creator,
AudioUnitScope scope,
UInt32 numElements)
{
mCreator = creator;
mScope = scope;
if (mDelegate)
return mDelegate->Initialize(creator, scope, numElements);
SetNumberOfElements(numElements);
}
/*! @method SetNumberOfElements */
void SetNumberOfElements(UInt32 numElements);
/*! @method GetNumberOfElements */
UInt32 GetNumberOfElements() const
{
if (mDelegate)
return mDelegate->GetNumberOfElements();
return static_cast<UInt32>(mElements.size());
}
/*! @method GetElement */
AUElement * GetElement(UInt32 elementIndex) const
{
if (mDelegate)
return mDelegate->GetElement(elementIndex);
ElementVector::const_iterator i = mElements.begin() + elementIndex;
// catch passing -1 in as the elementIndex - causes a wrap around
return (i >= mElements.end() || i < mElements.begin()) ? NULL : *i;
}
/*! @method SafeGetElement */
AUElement * SafeGetElement(UInt32 elementIndex)
{
AUElement *element = GetElement(elementIndex);
if (element == NULL)
COMPONENT_THROW(kAudioUnitErr_InvalidElement);
return element;
}
/*! @method GetIOElement */
AUIOElement * GetIOElement(UInt32 elementIndex) const
{
AUElement *element = GetElement(elementIndex);
AUIOElement *ioel = element ? element->AsIOElement () : NULL;
if (!ioel)
COMPONENT_THROW (kAudioUnitErr_InvalidElement);
return ioel;
}
/*! @method HasElementWithName */
bool HasElementWithName () const;
/*! @method AddElementNamesToDict */
void AddElementNamesToDict (CFMutableDictionaryRef & inNameDict);
bool RestoreElementNames (CFDictionaryRef& inNameDict);
AudioUnitScope GetScope() const { return mScope; }
void SetDelegate(AUScopeDelegate* inDelegate) { mDelegate = inDelegate; }
/*! @method SaveState */
void SaveState(CFMutableDataRef data);
/*! @method RestoreState */
const UInt8 * RestoreState(const UInt8 *state);
private:
typedef std::vector<AUElement *> ElementVector;
/*! @var mCreator */
AUBase * mCreator;
/*! @var mScope */
AudioUnitScope mScope;
/*! @var mElements */
ElementVector mElements;
/*! @var mDelegate */
AUScopeDelegate * mDelegate;
};
#endif // __AUScopeElement_h__

View File

@@ -0,0 +1,370 @@
/*
File: ComponentBase.cpp
Abstract: ComponentBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "ComponentBase.h"
#include "CAXException.h"
#if TARGET_OS_MAC
pthread_mutex_t ComponentInitLocker::sComponentOpenMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_once_t ComponentInitLocker::sOnce = PTHREAD_ONCE_INIT;
void ComponentInitLocker::InitComponentInitLocker()
{
// have to do this because OS X lacks PTHREAD_MUTEX_RECURSIVE_INITIALIZER_NP
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&sComponentOpenMutex, &attr);
pthread_mutexattr_destroy(&attr);
}
#elif TARGET_OS_WIN32
CAGuard ComponentInitLocker::sComponentOpenGuard("sComponentOpenGuard");
#endif
ComponentBase::EInstanceType ComponentBase::sNewInstanceType;
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc);
#if !CA_USE_AUDIO_PLUGIN_ONLY && !TARGET_OS_WIN32
static OSStatus CMgr_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc);
#endif
ComponentBase::ComponentBase(AudioComponentInstance inInstance)
: mComponentInstance(inInstance),
mInstanceType(sNewInstanceType)
{
GetComponentDescription();
}
ComponentBase::~ComponentBase()
{
}
void ComponentBase::PostConstructor()
{
}
void ComponentBase::PreDestructor()
{
}
#define ACPI ((AudioComponentPlugInInstance *)self)
#define ACImp ((ComponentBase *)&ACPI->mInstanceStorage)
OSStatus ComponentBase::AP_Open(void *self, AudioUnit compInstance)
{
OSStatus result = noErr;
try {
ComponentInitLocker lock;
ComponentBase::sNewInstanceType = ComponentBase::kAudioComponentInstance;
ComponentBase *cb = (ComponentBase *)(*ACPI->mConstruct)(&ACPI->mInstanceStorage, compInstance);
cb->PostConstructor(); // allows base class to do additional initialization
// once the derived class is fully constructed
result = noErr;
}
COMPONENT_CATCH
if (result)
delete ACPI;
return result;
}
OSStatus ComponentBase::AP_Close(void *self)
{
OSStatus result = noErr;
try {
if (ACImp) {
ACImp->PreDestructor();
(*ACPI->mDestruct)(&ACPI->mInstanceStorage);
free(self);
}
}
COMPONENT_CATCH
return result;
}
#if !CA_USE_AUDIO_PLUGIN_ONLY
OSStatus ComponentBase::Version()
{
return 0x00000001;
}
OSStatus ComponentBase::ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This)
{
if (This == NULL) return kAudio_ParamError;
OSStatus result = noErr;
switch (p->what) {
case kComponentCloseSelect:
This->PreDestructor();
delete This;
break;
case kComponentVersionSelect:
result = This->Version();
break;
case kComponentCanDoSelect:
switch (GetSelectorForCanDo(p)) {
case kComponentOpenSelect:
case kComponentCloseSelect:
case kComponentVersionSelect:
case kComponentCanDoSelect:
return 1;
default:
return 0;
}
default:
result = badComponentSelector;
break;
}
return result;
}
SInt16 ComponentBase::GetSelectorForCanDo(ComponentParameters *params)
{
if (params->what != kComponentCanDoSelect) return 0;
#if TARGET_CPU_X86
SInt16 sel = params->params[0];
#elif TARGET_CPU_X86_64
SInt16 sel = params->params[1];
#elif TARGET_CPU_PPC
SInt16 sel = (params->params[0] >> 16);
#else
SInt16 sel = params->params[0];
#endif
return sel;
/*
printf ("flags:%d, paramSize: %d, what: %d\n\t", params->flags, params->paramSize, params->what);
for (int i = 0; i < params->paramSize; ++i) {
printf ("[%d]:%d(0x%x), ", i, params->params[i], params->params[i]);
}
printf("\n\tsel:%d\n", sel);
*/
}
#endif
#if CA_DO_NOT_USE_AUDIO_COMPONENT
static OSStatus ComponentBase_GetComponentDescription (const AudioComponentInstance & inInstance, AudioComponentDescription &outDesc);
#endif
AudioComponentDescription ComponentBase::GetComponentDescription() const
{
AudioComponentDescription desc;
OSStatus result = 1;
if (IsPluginObject()) {
ca_require_noerr(result = CB_GetComponentDescription (mComponentInstance, &desc), home);
}
#if !CA_USE_AUDIO_PLUGIN_ONLY
else {
ca_require_noerr(result = CMgr_GetComponentDescription (mComponentInstance, &desc), home);
}
#endif
home:
if (result)
memset (&desc, 0, sizeof(AudioComponentDescription));
return desc;
}
#if CA_USE_AUDIO_PLUGIN_ONLY
// everything we need is there and we should be linking against it
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
{
AudioComponent comp = AudioComponentInstanceGetComponent(inInstance);
if (comp)
return AudioComponentGetDescription(comp, outDesc);
return kAudio_ParamError;
}
#elif !TARGET_OS_WIN32
// these are the direct dependencies on ComponentMgr calls that an AU
// that is a component mgr is dependent on
// these are dynamically loaded so that these calls will work on Leopard
#include <dlfcn.h>
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
{
typedef AudioComponent (*AudioComponentInstanceGetComponentProc) (AudioComponentInstance);
static AudioComponentInstanceGetComponentProc aciGCProc = NULL;
typedef OSStatus (*AudioComponentGetDescriptionProc)(AudioComponent, AudioComponentDescription *);
static AudioComponentGetDescriptionProc acGDProc = NULL;
static int doneInit = 0;
if (doneInit == 0) {
doneInit = 1;
void* theImage = dlopen("/System/Library/Frameworks/AudioUnit.framework/AudioUnit", RTLD_LAZY);
if (theImage != NULL)
{
aciGCProc = (AudioComponentInstanceGetComponentProc)dlsym (theImage, "AudioComponentInstanceGetComponent");
if (aciGCProc) {
acGDProc = (AudioComponentGetDescriptionProc)dlsym (theImage, "AudioComponentGetDescription");
}
}
}
OSStatus result = kAudio_UnimplementedError;
if (acGDProc && aciGCProc) {
AudioComponent comp = (*aciGCProc)(inInstance);
if (comp)
result = (*acGDProc)(comp, outDesc);
}
#if !CA_USE_AUDIO_PLUGIN_ONLY
else {
result = CMgr_GetComponentDescription (inInstance, outDesc);
}
#endif
return result;
}
#if !CA_USE_AUDIO_PLUGIN_ONLY
// these are the direct dependencies on ComponentMgr calls that an AU
// that is a component mgr is dependent on
// these are dynamically loaded
#include <CoreServices/CoreServices.h>
#include <AudioUnit/AudioUnit.h>
#include "CAXException.h"
#include "ComponentBase.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Component Manager
// Used for fast dispatch with audio units
typedef Handle (*GetComponentInstanceStorageProc)(ComponentInstance aComponentInstance);
static GetComponentInstanceStorageProc sGetComponentInstanceStorageProc = NULL;
typedef OSErr (*GetComponentInfoProc)(Component, ComponentDescription *, void*, void*, void*);
static GetComponentInfoProc sGetComponentInfoProc = NULL;
typedef void (*SetComponentInstanceStorageProc)(ComponentInstance, Handle);
static SetComponentInstanceStorageProc sSetComponentInstanceStorageProc = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void CSInitOnce(void* /*unused*/)
{
void *theImage = dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_LAZY);
if (!theImage) return;
sGetComponentInstanceStorageProc = (GetComponentInstanceStorageProc) dlsym(theImage, "GetComponentInstanceStorage");
sGetComponentInfoProc = (GetComponentInfoProc)dlsym (theImage, "GetComponentInfo");
sSetComponentInstanceStorageProc = (SetComponentInstanceStorageProc) dlsym(theImage, "SetComponentInstanceStorage");
}
#if TARGET_OS_MAC
#include <dispatch/dispatch.h>
static dispatch_once_t sCSInitOnce = 0;
static void CSInit ()
{
dispatch_once_f(&sCSInitOnce, NULL, CSInitOnce);
}
#else
static void CSInit ()
{
static int sDoCSLoad = 1;
if (sDoCSLoad) {
sDoCSLoad = 0;
CSInitOnce(NULL);
}
}
#endif
OSStatus CMgr_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
{
CSInit();
if (sGetComponentInfoProc)
return (*sGetComponentInfoProc)((Component)inInstance, (ComponentDescription*)outDesc, NULL, NULL, NULL);
return kAudio_UnimplementedError;
}
Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance)
{
CSInit();
if (sGetComponentInstanceStorageProc)
return (*sGetComponentInstanceStorageProc)(aComponentInstance);
return NULL;
}
void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage)
{
CSInit();
if (sSetComponentInstanceStorageProc)
(*sSetComponentInstanceStorageProc)(aComponentInstance, theStorage);
}
#endif // !CA_USE_AUDIO_PLUGIN_ONLY
#else
//#include "ComponentManagerDependenciesWin.h"
// everything we need is there and we should be linking against it
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
{
AudioComponent comp = AudioComponentInstanceGetComponent(inInstance);
if (comp)
return AudioComponentGetDescription(comp, outDesc);
return kAudio_ParamError;
}
#endif

View File

@@ -0,0 +1,353 @@
/*
File: ComponentBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __ComponentBase_h__
#define __ComponentBase_h__
#include <new>
#include "CADebugMacros.h"
#include "CAXException.h"
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreAudio/CoreAudioTypes.h>
#include <AudioUnit/AudioUnit.h>
#if !CA_USE_AUDIO_PLUGIN_ONLY
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h>
#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
#define AudioComponentInstance ComponentInstance
#define AudioComponentDescription ComponentDescription
#define AudioComponent Component
#endif
Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance);
void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage);
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
typedef Float32 AudioUnitParameterValue;
#endif
#if COREAUDIOTYPES_VERSION < 1051
typedef Float32 AudioUnitSampleType;
#endif
#if !TARGET_OS_WIN32
#include <pthread.h>
#endif
#if TARGET_OS_WIN32
#include "CAGuard.h"
#endif
#else
#include "CoreAudioTypes.h"
#if !CA_USE_AUDIO_PLUGIN_ONLY
#include "ComponentManagerDependenciesWin.h"
#endif
#include "AudioUnit.h"
#include "CAGuard.h"
#endif
#ifndef COMPONENT_THROW
#if VERBOSE_COMPONENT_THROW
#define COMPONENT_THROW(throw_err) \
do { DebugMessage(#throw_err); throw static_cast<OSStatus>(throw_err); } while (0)
#else
#define COMPONENT_THROW(throw_err) \
throw static_cast<OSStatus>(throw_err)
#endif
#endif
#define COMPONENT_CATCH \
catch (const CAXException &ex) { result = ex.mError; } \
catch (std::bad_alloc &) { result = kAudio_MemFullError; } \
catch (OSStatus catch_err) { result = catch_err; } \
catch (OSErr catch_err) { result = catch_err; } \
catch (...) { result = -1; }
/*! @class ComponentBase */
class ComponentBase {
public:
// classic MacErrors
enum { noErr = 0};
/*! @ctor ComponentBase */
ComponentBase(AudioComponentInstance inInstance);
/*! @dtor ~ComponentBase */
virtual ~ComponentBase();
/*! @method PostConstructor */
virtual void PostConstructor();
/*! @method PreDestructor */
virtual void PreDestructor();
#if !CA_USE_AUDIO_PLUGIN_ONLY
/*! @method Version */
virtual OSStatus Version();
/*! @method ComponentEntryDispatch */
static OSStatus ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This);
/*! GetSelectorForCanDo */
static SInt16 GetSelectorForCanDo(ComponentParameters *params);
#endif
/*! @method GetComponentInstance */
AudioComponentInstance GetComponentInstance() const { return mComponentInstance; }
/*! @method GetComponentDescription */
AudioComponentDescription GetComponentDescription() const;
// This global variable is so that new instances know how they were instantiated: via the Component Manager,
// or as AudioComponents. It's ugly, but preferable to altering the constructor of every class in the hierarchy.
// It's safe because construction is protected by ComponentInitLocker.
enum EInstanceType { kComponentMgrInstance, kAudioComponentInstance };
static EInstanceType sNewInstanceType;
/*! @method IsPluginObject */
bool IsPluginObject () const { return mInstanceType == kAudioComponentInstance; }
/*! @method IsCMgrObject */
bool IsCMgrObject () const { return mInstanceType == kComponentMgrInstance; }
/*! @method AP_Open */
static OSStatus AP_Open(void *self, AudioUnit compInstance);
/*! @method AP_Close */
static OSStatus AP_Close(void *self);
protected:
/*! @var mComponentInstance */
AudioComponentInstance mComponentInstance;
EInstanceType mInstanceType;
};
class ComponentInitLocker
{
#if TARGET_OS_MAC
public:
ComponentInitLocker()
{
pthread_once(&sOnce, InitComponentInitLocker);
pthread_mutex_lock(&sComponentOpenMutex);
mPreviousNewInstanceType = ComponentBase::sNewInstanceType;
}
~ComponentInitLocker()
{
ComponentBase::sNewInstanceType = mPreviousNewInstanceType;
pthread_mutex_unlock(&sComponentOpenMutex);
}
// There are situations (11844772) where we need to be able to release the lock early.
class Unlocker {
public:
Unlocker()
{
pthread_mutex_unlock(&sComponentOpenMutex);
}
~Unlocker()
{
pthread_mutex_lock(&sComponentOpenMutex);
}
};
private:
static pthread_mutex_t sComponentOpenMutex;
static pthread_once_t sOnce;
static void InitComponentInitLocker();
#elif TARGET_OS_WIN32
public:
bool sNeedsUnlocking;
ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); }
~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } }
private:
static CAGuard sComponentOpenGuard;
#endif
private:
ComponentBase::EInstanceType mPreviousNewInstanceType;
};
/*! @class AudioComponentPlugInInstance */
struct AudioComponentPlugInInstance {
AudioComponentPlugInInterface mPlugInInterface;
void * (*mConstruct)(void *memory, AudioComponentInstance ci);
void (*mDestruct)(void *memory);
void * mPad[2]; // pad to a 16-byte boundary (in either 32 or 64 bit mode)
UInt32 mInstanceStorage; // the ACI implementation object is constructed into this memory
// this member is just a placeholder. it is aligned to a 16byte boundary
};
/*! @class APFactory */
template <class APMethodLookup, class Implementor>
class APFactory {
public:
static void *Construct(void *memory, AudioComponentInstance compInstance)
{
return new(memory) Implementor(compInstance);
}
static void Destruct(void *memory)
{
((Implementor *)memory)->~Implementor();
}
// This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance.
// The actual implementation object is not created until Open().
static AudioComponentPlugInInterface *Factory(const AudioComponentDescription * /* inDesc */)
{
AudioComponentPlugInInstance *acpi =
(AudioComponentPlugInInstance *)malloc( offsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor) );
acpi->mPlugInInterface.Open = ComponentBase::AP_Open;
acpi->mPlugInInterface.Close = ComponentBase::AP_Close;
acpi->mPlugInInterface.Lookup = APMethodLookup::Lookup;
acpi->mPlugInInterface.reserved = NULL;
acpi->mConstruct = Construct;
acpi->mDestruct = Destruct;
acpi->mPad[0] = NULL;
acpi->mPad[1] = NULL;
return (AudioComponentPlugInInterface*)acpi;
}
// This is for runtime registration (not for plug-ins loaded from bundles).
static AudioComponent Register(UInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags=0)
{
AudioComponentDescription desc = { type, subtype, manuf, flags, 0 };
return AudioComponentRegister(&desc, name, vers, Factory);
}
};
#if !CA_USE_AUDIO_PLUGIN_ONLY
/*! @class ComponentEntryPoint
* @discussion This is only used for a component manager version
*/
template <class Class>
class ComponentEntryPoint {
public:
/*! @method Dispatch */
static OSStatus Dispatch(ComponentParameters *params, Class *obj)
{
OSStatus result = noErr;
try {
if (params->what == kComponentOpenSelect) {
// solve a host of initialization thread safety issues.
ComponentInitLocker lock;
ComponentBase::sNewInstanceType = ComponentBase::kComponentMgrInstance;
ComponentInstance ci = (ComponentInstance)(params->params[0]);
Class *This = new Class((AudioComponentInstance)ci);
This->PostConstructor(); // allows base class to do additional initialization
// once the derived class is fully constructed
CMgr_SetComponentInstanceStorage(ci, (Handle)This);
} else
result = Class::ComponentEntryDispatch(params, obj);
}
COMPONENT_CATCH
return result;
}
/*! @method Register */
static Component Register(OSType compType, OSType subType, OSType manufacturer)
{
ComponentDescription description = {compType, subType, manufacturer, 0, 0};
Component component = RegisterComponent(&description, (ComponentRoutineUPP) Dispatch, registerComponentGlobal, NULL, NULL, NULL);
if (component != NULL) {
SetDefaultComponent(component, defaultComponentAnyFlagsAnyManufacturerAnySubType);
}
return component;
}
};
// NOTE: Component Mgr is deprecated in ML.
// this macro should not be used with new audio components
// it is only for backwards compatibility with Lion and SL.
// this macro registers both a plugin and a component mgr version.
#define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \
return ComponentEntryPoint<Class>::Dispatch(params, obj); \
} \
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \
return FactoryType<Class>::Factory(inDesc); \
}
// the only component we still support are the carbon based view components
// you should be using this macro now to exclusively register those types
#define VIEW_COMPONENT_ENTRY(Class) \
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \
return ComponentEntryPoint<Class>::Dispatch(params, obj); \
}
/*! @class ComponentRegistrar */
template <class Class, OSType Type, OSType Subtype, OSType Manufacturer>
class ComponentRegistrar {
public:
/*! @ctor ComponentRegistrar */
ComponentRegistrar() { ComponentEntryPoint<Class>::Register(Type, Subtype, Manufacturer); }
};
#define COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \
static ComponentRegistrar<Class, Type, Subtype, Manufacturer> gRegistrar##Class
#else
#define COMPONENT_ENTRY(Class)
#define COMPONENT_REGISTER(Class)
// this macro is used to generate the Entry Point for a given Audio Plugin
// you should be using this macro now with audio components
#define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \
return FactoryType<Class>::Factory(inDesc); \
}
#endif // !CA_USE_AUDIO_PLUGIN_ONLY
#endif // __ComponentBase_h__

View File

@@ -0,0 +1,403 @@
/*
File: AUCarbonViewBase.cpp
Abstract: AUCarbonViewBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUCarbonViewBase.h"
#include "AUCarbonViewControl.h"
#include <algorithm>
AUCarbonViewBase::AUCarbonViewBase(AudioUnitCarbonView inInstance, Float32 inNotificationInterval /* in seconds */) :
ComponentBase(inInstance),
mEditAudioUnit(0),
mParameterListener(NULL),
#if !__LP64__
mEventListener(NULL),
#endif
mTimerRef (NULL),
mTimerUPP (NULL),
mCarbonWindow(NULL),
mCarbonPane(NULL),
mXOffset(0),
mYOffset(0)
{
AUEventListenerCreate (ParameterListener, this,
CFRunLoopGetCurrent(), kCFRunLoopCommonModes,
inNotificationInterval, inNotificationInterval,
&mParameterListener);
}
AUCarbonViewBase::~AUCarbonViewBase()
{
#if !__LP64__
if (mCarbonPane)
DisposeControl(mCarbonPane);
for (ControlList::iterator it = mControlList.begin(); it != mControlList.end(); ++it) {
AUCarbonViewControl *ctl = *it;
delete ctl;
}
AUListenerDispose(mParameterListener);
if (mTimerRef)
::RemoveEventLoopTimer (mTimerRef);
if (mTimerUPP)
DisposeEventLoopTimerUPP (mTimerUPP);
#endif
}
void AUCarbonViewBase::AddControl(AUCarbonViewControl *control)
{
ControlList::iterator it = find(mControlList.begin(), mControlList.end(), control);
if (it == mControlList.end())
mControlList.push_back(control);
}
void AUCarbonViewBase::RemoveControl(AUCarbonViewControl *control)
{
ControlList::iterator it = find(mControlList.begin(), mControlList.end(), control);
if (it != mControlList.end()) {
AUCarbonViewControl *ctl = *it;
mControlList.erase(it);
delete ctl;
}
}
void AUCarbonViewBase::ClearControls ()
{
for (ControlList::iterator it = mControlList.begin(); it != mControlList.end(); ++it) {
AUCarbonViewControl *ctl = *it;
delete ctl;
}
mControlList.clear();
}
void AUCarbonViewBase::ParameterListener(void * inCallbackRefCon,
void * inObject,
const AudioUnitEvent * inEvent,
UInt64 inEventHostTime,
Float32 inParameterValue)
{
if (inEvent->mEventType == kAudioUnitEvent_ParameterValueChange) {
AUCarbonViewControl *ctl = (AUCarbonViewControl *)inObject;
ctl->ParameterToControl(inParameterValue);
}
}
OSStatus AUCarbonViewBase::CreateCarbonView(AudioUnit inAudioUnit, WindowRef inWindow, ControlRef inParentControl, const Float32Point &inLocation, const Float32Point &inSize, ControlRef &outParentControl)
{
#if !__LP64__
mEditAudioUnit = inAudioUnit;
mCarbonWindow = inWindow;
WindowAttributes attributes;
verify_noerr(GetWindowAttributes(mCarbonWindow, &attributes));
mCompositWindow = (attributes & kWindowCompositingAttribute) != 0;
Rect area;
area.left = short(inLocation.x); area.top = short(inLocation.y);
area.right = short(area.left + inSize.x); area.bottom = short(area.top + inSize.y);
OSStatus err = ::CreateUserPaneControl(inWindow, &area,
kControlSupportsEmbedding,
&mCarbonPane); // subclass can resize mCarbonPane to taste
verify_noerr(err);
if (err) return err;
outParentControl = mCarbonPane;
// register for mouse-down in our pane -- we want to clear focus
EventTypeSpec paneEvents[] = {
{ kEventClassControl, kEventControlClick }
};
WantEventTypes(GetControlEventTarget(mCarbonPane), GetEventTypeCount(paneEvents), paneEvents);
if (IsCompositWindow()) {
verify_noerr(::HIViewAddSubview(inParentControl, mCarbonPane));
mXOffset = 0;
mYOffset = 0;
}
else {
verify_noerr(::EmbedControl(mCarbonPane, inParentControl));
mXOffset = inLocation.x;
mYOffset = inLocation.y;
}
mBottomRight.h = mBottomRight.v = 0;
SizeControl(mCarbonPane, 0, 0);
if (err = CreateUI(mXOffset, mYOffset))
return err;
// we should only resize the control if a subclass has embedded
// controls in this AND this is done with the EmbedControl call below
// if mBottomRight is STILL equal to zero, then that wasn't done
// so don't size the control
Rect paneBounds;
GetControlBounds(mCarbonPane, &paneBounds);
// only resize mCarbonPane if it has not already been resized during CreateUI
if ((paneBounds.top == paneBounds.bottom) && (paneBounds.left == paneBounds.right)) {
if (mBottomRight.h != 0 && mBottomRight.v != 0)
SizeControl(mCarbonPane, (short) (mBottomRight.h - mXOffset), (short) (mBottomRight.v - mYOffset));
}
if (IsCompositWindow()) {
// prepare for handling scroll-events
EventTypeSpec scrollEvents[] = {
{ kEventClassScrollable, kEventScrollableGetInfo },
{ kEventClassScrollable, kEventScrollableScrollTo }
};
WantEventTypes(GetControlEventTarget(mCarbonPane), GetEventTypeCount(scrollEvents), scrollEvents);
mCurrentScrollPoint.x = mCurrentScrollPoint.y = 0.0f;
}
return err;
#else
return noErr;
#endif
}
OSStatus AUCarbonViewBase::CreateUI(Float32 inXOffset, Float32 inYOffset)
{
return noErr;
}
OSStatus AUCarbonViewBase::EmbedControl(ControlRef ctl)
{
#if !__LP64__
Rect r;
::GetControlBounds(ctl, &r);
if (r.right > mBottomRight.h) mBottomRight.h = r.right;
if (r.bottom > mBottomRight.v) mBottomRight.v = r.bottom;
if (IsCompositWindow())
return ::HIViewAddSubview(mCarbonPane, ctl);
else
return ::EmbedControl(ctl, mCarbonPane);
#else
return noErr;
#endif
}
void AUCarbonViewBase::AddCarbonControl(AUCarbonViewControl::ControlType type, const CAAUParameter &param, ControlRef control)
{
verify_noerr(EmbedControl(control));
AUCarbonViewControl *auvc = new AUCarbonViewControl(this, mParameterListener, type, param, control);
auvc->Bind();
AddControl(auvc);
}
bool AUCarbonViewBase::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event)
{
#if !__LP64__
UInt32 eclass = GetEventClass(event);
UInt32 ekind = GetEventKind(event);
ControlRef control;
switch (eclass) {
case kEventClassControl:
{
switch (ekind) {
case kEventControlClick:
GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
if (control == mCarbonPane) {
ClearKeyboardFocus(mCarbonWindow);
return true;
}
}
}
break;
case kEventClassScrollable:
{
switch (ekind) {
case kEventScrollableGetInfo:
{
// [1/4]
/* <-- kEventParamImageSize (out, typeHISize)
* On exit, contains the size of the entire scrollable view.
*/
HISize originalSize = { mBottomRight.h, mBottomRight.v };
verify_noerr(SetEventParameter(event, kEventParamImageSize, typeHISize, sizeof(HISize), &originalSize));
// [2/4]
/* <-- kEventParamViewSize (out, typeHISize)
* On exit, contains the amount of the scrollable view that is
* visible.
*/
HIViewRef parentView = HIViewGetSuperview(mCarbonPane);
HIRect parentBounds;
verify_noerr(HIViewGetBounds(parentView, &parentBounds));
//HISize windowSize = { float(windowBounds.right - windowBounds.left),
// float(windowBounds.bottom - windowBounds.top) };
verify_noerr(SetEventParameter(event, kEventParamViewSize, typeHISize, sizeof(HISize), &(parentBounds.size)));
// [3/4]
/* <-- kEventParamLineSize (out, typeHISize)
* On exit, contains the amount that should be scrolled in
* response to a single click on a scrollbar arrow.
*/
HISize scrollIncrementSize = { 16.0f, float(20) };
verify_noerr(SetEventParameter(event, kEventParamLineSize, typeHISize, sizeof(HISize), &scrollIncrementSize));
// [4/4]
/* <-- kEventParamOrigin (out, typeHIPoint)
* On exit, contains the scrollable view<65>s current origin (the
* view-relative coordinate that is drawn at the top left
* corner of its frame). These coordinates should always be
* greater than or equal to zero. They should be less than or
* equal to the view<65>s image size minus its view size.
*/
verify_noerr(SetEventParameter(event, kEventParamOrigin, typeHIPoint, sizeof(HIPoint), &mCurrentScrollPoint));
}
return true;
case kEventScrollableScrollTo:
{
/*
* kEventClassScrollable / kEventScrollableScrollTo
*
* Summary:
* Requests that an HIScrollView<65>s scrollable view should scroll to
* a particular origin.
*/
/* --> kEventParamOrigin (in, typeHIPoint)
* The new origin for the scrollable view. The origin
* coordinates will vary from (0,0) to scrollable view<65>s image
* size minus its view size.
*/
HIPoint pointToScrollTo;
verify_noerr(GetEventParameter(event, kEventParamOrigin, typeHIPoint, NULL, sizeof(HIPoint), NULL, &pointToScrollTo));
float xDelta = mCurrentScrollPoint.x - pointToScrollTo.x;
float yDelta = mCurrentScrollPoint.y - pointToScrollTo.y;
// move visible portion the appropriate amount
verify_noerr(HIViewScrollRect(mCarbonPane, NULL, xDelta, yDelta));
// set new content to be drawn
verify_noerr(HIViewSetBoundsOrigin(mCarbonPane, pointToScrollTo.x, pointToScrollTo.y));
mCurrentScrollPoint = pointToScrollTo;
}
return true;
default:
break;
}
}
break;
default:
break;
}
#endif
return false;
}
/*! @method TellListener */
void AUCarbonViewBase::TellListener (const CAAUParameter &auvp, AudioUnitCarbonViewEventID event, void *evpar)
{
#if !__LP64__
if (mEventListener)
(*mEventListener)(mEventListenerUserData, mComponentInstance, &auvp, event, evpar);
#endif
AudioUnitEvent auEvent;
auEvent.mArgument.mParameter = auvp;
if (event == kAudioUnitCarbonViewEvent_MouseDownInControl) {
auEvent.mEventType = kAudioUnitEvent_BeginParameterChangeGesture;
} else {
auEvent.mEventType = kAudioUnitEvent_EndParameterChangeGesture;
}
AUEventListenerNotify(mParameterListener, this, &auEvent);
}
void AUCarbonViewBase::Update (bool inUIThread)
{
for (ControlList::iterator iter = mControlList.begin(); iter != mControlList.end(); ++iter)
{
(*iter)->Update(inUIThread);
}
}
pascal void AUCarbonViewBase::TheTimerProc (EventLoopTimerRef inTimer, void *inUserData)
{
AUCarbonViewBase* This = reinterpret_cast<AUCarbonViewBase*>(inUserData);
This->RespondToEventTimer (inTimer);
}
void AUCarbonViewBase::RespondToEventTimer (EventLoopTimerRef inTimer)
{}
/*
THESE are reasonable values for these two times
0.005 // delay
0.050 // interval
*/
OSStatus AUCarbonViewBase::CreateEventLoopTimer (Float32 inDelay, Float32 inInterval)
{
if (mTimerUPP)
return noErr;
mTimerUPP = NewEventLoopTimerUPP(TheTimerProc);
EventLoopRef mainEventLoop = GetMainEventLoop();
//doesn't seem to like too small a value
if (inDelay < 0.005)
inDelay = 0.005;
OSStatus timerResult = ::InstallEventLoopTimer(
mainEventLoop,
inDelay,
inInterval,
mTimerUPP,
this,
&mTimerRef);
return timerResult;
}

View File

@@ -0,0 +1,188 @@
/*
File: AUCarbonViewBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUCarbonViewBase_h__
#define __AUCarbonViewBase_h__
#include <vector>
#include "AUCarbonViewControl.h"
#include "ComponentBase.h"
static const Float32 kDefaultNotificationInterval = 0.100;
/*! @class AUCarbonViewBase */
class AUCarbonViewBase : public ComponentBase, public CarbonEventHandler
{
public:
/*! @ctor AUCarbonViewBase */
AUCarbonViewBase ( AudioUnitCarbonView inInstance,
Float32 inNotificationInterval = kDefaultNotificationInterval /* in seconds */);
/*! @dtor ~AUCarbonViewBase */
virtual ~AUCarbonViewBase();
// AUViewBase overrides
/*! @method CreateCarbonView */
virtual OSStatus CreateCarbonView (AudioUnit inAudioUnit, WindowRef inWindow, ControlRef inParentControl, const Float32Point &inLocation, const Float32Point &inSize, ControlRef &outParentControl);
// our own virtual methods
/*! @method CreateUI */
virtual OSStatus CreateUI (Float32 inXOffset, Float32 inYOffset);
/*! @method HandleEvent */
virtual bool HandleEvent (EventHandlerCallRef inHandlerRef, EventRef event);
/*! @method GetEditAudioUnit */
const AudioUnit GetEditAudioUnit () const { return mEditAudioUnit; }
//
/*! @method ComponentEntryDispatch */
static OSStatus ComponentEntryDispatch (
ComponentParameters * params,
AUCarbonViewBase * This);
/*! @method AddCarbonControl */
void AddCarbonControl (
AUCarbonViewControl::ControlType type,
const CAAUParameter & param,
ControlRef control);
/*! @method GetCarbonWindow */
WindowRef GetCarbonWindow () { return mCarbonWindow; }
/*! @method GetCarbonPane */
ControlRef GetCarbonPane () { return mCarbonPane; }
/*! @method EmbedControl */
OSStatus EmbedControl (ControlRef ctl);
/*! @method TellListener */
void TellListener (const CAAUParameter &auvp, AudioUnitCarbonViewEventID event, void *evpar);
// pass in true if wanting an update to the view and you're calling this from a thread
// that is safe to do UI in.
// If you don't know, pass in false!
/*! @method Update */
void Update (bool inUIThread);
/*! @method GetXOffset */
Float32 GetXOffset () { return mXOffset; }
/*! @method GetYOffset */
Float32 GetYOffset () { return mYOffset; }
/*! @method ClearControls */
void ClearControls ();
/*! @method IsCompositWindow */
bool IsCompositWindow () const { return mCompositWindow; }
protected:
#if !__LP64__
/*! @method SetEventListener */
void SetEventListener (AudioUnitCarbonViewEventListener listener, void *userData)
{
mEventListener = listener;
mEventListenerUserData = userData;
}
#endif
/*! @method AddControl */
void AddControl (AUCarbonViewControl *control);
/*! @method RemoveControl */
void RemoveControl (AUCarbonViewControl *control);
OSStatus CreateEventLoopTimer (Float32 inDelay, Float32 inInterval);
/*! @method ParameterListener */
static void ParameterListener (void * inCallbackRefCon,
void * inObject,
const AudioUnitEvent * inEvent,
UInt64 inEventHostTime,
Float32 inParameterValue);
static pascal void TheTimerProc ( EventLoopTimerRef inTimer,
void * inUserData);
virtual void RespondToEventTimer (EventLoopTimerRef inTimer);
/*! @var mEditAudioUnit */
AudioUnit mEditAudioUnit; // the AU we're controlling
/*! @var mParameterListener */
AUEventListenerRef mParameterListener;
#if !__LP64__
/*! @var mEventListener */
AudioUnitCarbonViewEventListener
mEventListener;
#endif
/*! @var mEventListenerUserData */
void * mEventListenerUserData;
private:
typedef std::vector<AUCarbonViewControl *> ControlList;
/*! @var mControlList */
ControlList mControlList;
EventLoopTimerRef mTimerRef;
EventLoopTimerUPP mTimerUPP;
protected:
/*! @var mCarbonWindow */
WindowRef mCarbonWindow;
/*! @var mCarbonPane */
ControlRef mCarbonPane; // user pane, contains all other controls
/*! @var mBottomRight */
Point mBottomRight; // largest width and height of child controls
/*! @var mXOffset */
Float32 mXOffset;
/*! @var mYOffset */
Float32 mYOffset;
/*! @var mCompositWindow */
bool mCompositWindow;
/*! @var mCurrentScrollPoint */
HIPoint mCurrentScrollPoint; // needed for scrolling
};
#endif // __AUCarbonViewBase_h__

View File

@@ -0,0 +1,710 @@
/*
File: AUCarbonViewControl.cpp
Abstract: AUCarbonViewControl.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUCarbonViewControl.h"
#include "AUCarbonViewBase.h"
#include "AUViewLocalizedStringKeys.h"
AUCarbonViewControl::AUCarbonViewControl(AUCarbonViewBase *ownerView, AUParameterListenerRef listener, ControlType type, const CAAUParameter &param, ControlRef control) :
mOwnerView(ownerView),
mListener(listener),
mType(type),
mParam(param),
mControl(control),
mInControlInitialization(0)
{
#if !__LP64__
SetControlReference(control, SRefCon(this));
#endif
}
AUCarbonViewControl::~AUCarbonViewControl()
{
AUListenerRemoveParameter(mListener, this, &mParam);
}
AUCarbonViewControl* AUCarbonViewControl::mLastControl = NULL;
void AUCarbonViewControl::Bind()
{
#if !__LP64__
mInControlInitialization = 1; // true
AUListenerAddParameter(mListener, this, &mParam);
// will cause an almost-immediate callback
EventTypeSpec events[] = {
{ kEventClassControl, kEventControlValueFieldChanged } // N.B. OS X only
};
WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
if (mType == kTypeContinuous || mType == kTypeText || mType == kTypeDiscrete) {
EventTypeSpec events[] = {
{ kEventClassControl, kEventControlHit },
{ kEventClassControl, kEventControlClick },
{ kEventClassControl, kEventControlTrack }
};
WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
}
if (mType == kTypeText) {
EventTypeSpec events[] = {
{ kEventClassControl, kEventControlSetFocusPart }
};
WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
ControlKeyFilterUPP proc = mParam.ValuesHaveStrings() ? StdKeyFilterCallback : NumericKeyFilterCallback;
// this will fail for a static text field
SetControlData(mControl, 0, kControlEditTextKeyFilterTag, sizeof(proc), &proc);
}
Update(true);
mInControlInitialization = 0; // false
#endif
}
void AUCarbonViewControl::ParameterToControl(Float32 paramValue)
{
#if !__LP64__
++mInControlInitialization;
switch (mType) {
case kTypeContinuous:
SetValueFract(AUParameterValueToLinear(paramValue, &mParam));
break;
case kTypeDiscrete:
{
long value = long(paramValue);
// special case [1] -- menu parameters
if (mParam.HasNamedParams()) {
// if we're dealing with menus they behave differently!
// becaue setting min and max doesn't work correctly for the control value
// first menu item always reports a control value of 1
ControlKind ctrlKind;
if (GetControlKind(mControl, &ctrlKind) == noErr) {
if ((ctrlKind.kind == kControlKindPopupArrow)
|| (ctrlKind.kind == kControlKindPopupButton))
{
value = value - long(mParam.ParamInfo().minValue) + 1;
}
}
}
// special case [2] -- Write-only boolean parameters
AudioUnitParameterInfo AUPI = mParam.ParamInfo();
bool isWriteOnlyBoolParameter = ( (AUPI.unit == kAudioUnitParameterUnit_Boolean) &&
(AUPI.flags & kAudioUnitParameterFlag_IsWritable) &&
!(AUPI.flags & kAudioUnitParameterFlag_IsReadable) );
if (!isWriteOnlyBoolParameter) {
SetValue (value);
}
}
break;
case kTypeText:
{
CFStringRef cfstr = mParam.GetStringFromValueCopy(&paramValue);
if ( !(mParam.ParamInfo().flags & kAudioUnitParameterFlag_IsWritable) //READ ONLY PARAMS
&& (mParam.ParamInfo().flags & kAudioUnitParameterFlag_IsReadable))
{
if (mParam.GetParamTag()) {
CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 256, cfstr);
CFRelease (cfstr);
CFStringAppend (str, CFSTR(" "));
CFStringAppend (str, mParam.GetParamTag());
cfstr = str;
}
}
SetTextValue(cfstr);
CFRelease (cfstr);
}
break;
}
--mInControlInitialization;
#endif
}
void AUCarbonViewControl::ControlToParameter()
{
#if !__LP64__
if (mInControlInitialization)
return;
switch (mType) {
case kTypeContinuous:
{
double controlValue = GetValueFract();
Float32 paramValue = AUParameterValueFromLinear(controlValue, &mParam);
mParam.SetValue(mListener, this, paramValue);
}
break;
case kTypeDiscrete:
{
long value = GetValue();
// special case [1] -- Menus
if (mParam.HasNamedParams()) {
// if we're dealing with menus they behave differently!
// becaue setting min and max doesn't work correctly for the control value
// first menu item always reports a control value of 1
ControlKind ctrlKind;
if (GetControlKind(mControl, &ctrlKind) == noErr) {
if ((ctrlKind.kind == kControlKindPopupArrow)
|| (ctrlKind.kind == kControlKindPopupButton))
{
value = value + long(mParam.ParamInfo().minValue) - 1;
}
}
}
// special case [2] -- Write-only boolean parameters
AudioUnitParameterInfo AUPI = mParam.ParamInfo();
bool isWriteOnlyBoolParameter = ( (AUPI.unit == kAudioUnitParameterUnit_Boolean) &&
(AUPI.flags & kAudioUnitParameterFlag_IsWritable) &&
!(AUPI.flags & kAudioUnitParameterFlag_IsReadable) );
if (isWriteOnlyBoolParameter) {
value = 1;
}
mParam.SetValue (mListener, this, value);
}
break;
case kTypeText:
{
Float32 val = mParam.GetValueFromString (GetTextValue());
mParam.SetValue(mListener, this, (mParam.IsIndexedParam() ? (int)val : val));
if (mParam.ValuesHaveStrings())
ParameterToControl(val); //make sure we display the correct text (from the AU)
}
break;
}
#endif
}
void AUCarbonViewControl::SetValueFract(double value)
{
#if !__LP64__
SInt32 minimum = GetControl32BitMinimum(mControl);
SInt32 maximum = GetControl32BitMaximum(mControl);
SInt32 cval = SInt32(value * (maximum - minimum) + minimum + 0.5);
SetControl32BitValue(mControl, cval);
// printf("set: value=%lf, min=%ld, max=%ld, ctl value=%ld\n", value, minimum, maximum, cval);
#endif
}
double AUCarbonViewControl::GetValueFract()
{
#if !__LP64__
SInt32 minimum = GetControl32BitMinimum(mControl);
SInt32 maximum = GetControl32BitMaximum(mControl);
SInt32 cval = GetControl32BitValue(mControl);
double result = double(cval - minimum) / double(maximum - minimum);
// printf("get: min=%ld, max=%ld, value=%ld, result=%f\n", minimum, maximum, cval, result);
return result;
#else
return 0;
#endif
}
void AUCarbonViewControl::SetTextValue(CFStringRef cfstr)
{
#if !__LP64__
verify_noerr(SetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr));
#endif
}
CFStringRef AUCarbonViewControl::GetTextValue()
{
#if !__LP64__
CFStringRef cfstr;
verify_noerr(GetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr, NULL));
return cfstr;
#else
return CFSTR("");
#endif
}
void AUCarbonViewControl::SetValue(long value)
{
#if !__LP64__
SetControl32BitValue(mControl, value);
#endif
}
long AUCarbonViewControl::GetValue()
{
#if !__LP64__
return GetControl32BitValue(mControl);
#else
return 0;
#endif
}
/* Notes on event handling
Button (Click and release on button)
kEventControlClick received
kEventControlTrack received
kEventControlValueFieldChanged received
kEventControlHit received
Button (Click and release outside of button bounds)
kEventControlClick received
kEventControlTrack received
Slider (Click, drag, and release)
kEventControlClick received
kEventControlTrack received
kEventControlValueFieldChanged received
kEventControlValueFieldChanged received
kEventControlHit received
Slider (Click, release without changing value)
kEventControlClick received
kEventControlTrack received
*/
bool AUCarbonViewControl::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event)
{
UInt32 eclass = GetEventClass(event);
UInt32 ekind = GetEventKind(event);
ControlRef control;
bool handled = true;
switch (eclass) {
case kEventClassControl:
{
AudioUnitParameterInfo AUPI = mParam.ParamInfo();
bool isWriteOnlyBoolParameter = ( (AUPI.unit == kAudioUnitParameterUnit_Boolean) &&
(AUPI.flags & kAudioUnitParameterFlag_IsWritable) &&
!(AUPI.flags & kAudioUnitParameterFlag_IsReadable) );
switch (ekind) {
case kEventControlSetFocusPart: // tab
handled = !handled; // fall through to next case
mLastControl = this;
case kEventControlValueFieldChanged:
GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
verify(control == mControl);
ControlToParameter();
return handled;
case kEventControlClick:
if (isWriteOnlyBoolParameter) {
GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
verify(control == mControl);
ControlToParameter();
} else if (mLastControl != this) {
if (mLastControl != NULL) {
mLastControl->Update(false);
}
mLastControl = this;
}
mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseDownInControl, NULL);
break; // don't return true, continue normal processing
case kEventControlHit:
if (mLastControl != this) {
if (mLastControl != NULL)
mLastControl->Update(false);
mLastControl = this;
}
mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseUpInControl, NULL);
break; // don't return true, continue normal processing
case kEventControlTrack:
if (mLastControl != this) {
if (mLastControl != NULL)
mLastControl->Update(false);
mLastControl = this;
}
CallNextEventHandler(inHandlerRef, event);
ControlToParameter(); // new code
mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseUpInControl, NULL);
// old code:
// break; // don't return true, continue normal processing
return handled; // don't return true, continue normal processing
}
}
}
return !handled;
}
pascal void AUCarbonViewControl::SliderTrackProc(ControlRef theControl, ControlPartCode partCode)
{
// this doesn't need to actually do anything
// AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl);
}
pascal ControlKeyFilterResult AUCarbonViewControl::StdKeyFilterCallback(ControlRef theControl,
SInt16 *keyCode, SInt16 *charCode,
EventModifiers *modifiers)
{
#if !__LP64__
SInt16 c = *charCode;
if (c >= ' ' || c == '\b' || c == 0x7F || (c >= 0x1c && c <= 0x1f) || c == '\t')
return kControlKeyFilterPassKey;
if (c == '\r' || c == 3) { // return or Enter
AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl);
ControlEditTextSelectionRec sel = { 0, 32767 };
SetControlData(This->mControl, 0, kControlEditTextSelectionTag, sizeof(sel), &sel);
This->ControlToParameter();
}
#endif
return kControlKeyFilterBlockKey;
}
pascal ControlKeyFilterResult AUCarbonViewControl::NumericKeyFilterCallback(ControlRef theControl,
SInt16 *keyCode, SInt16 *charCode,
EventModifiers *modifiers)
{
#if !__LP64__
SInt16 c = *charCode;
if (isdigit(c) || c == '+' || c == '-' || c == '.' || c == '\b' || c == 0x7F || (c >= 0x1c && c <= 0x1f)
|| c == '\t')
return kControlKeyFilterPassKey;
if (c == '\r' || c == 3) { // return or Enter
AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl);
ControlEditTextSelectionRec sel = { 0, 32767 };
SetControlData(This->mControl, 0, kControlEditTextSelectionTag, sizeof(sel), &sel);
This->ControlToParameter();
}
#endif
return kControlKeyFilterBlockKey;
}
Boolean AUCarbonViewControl::SizeControlToFit(ControlRef inControl, SInt16 *outWidth, SInt16 *outHeight)
{
#if !__LP64__
if (inControl == 0) return false;
Boolean bValue = false;
// this only works on text controls -- returns an error for other controls, but doesn't do anything,
// so the error is irrelevant
SetControlData(inControl, kControlEntireControl, 'stim' /* kControlStaticTextIsMultilineTag */, sizeof(Boolean), &bValue);
SInt16 baseLineOffset;
Rect bestRect;
OSErr err = GetBestControlRect(inControl, &bestRect, &baseLineOffset);
if (err != noErr) return false;
int width = (bestRect.right - bestRect.left) + 1;
int height = (bestRect.bottom - bestRect.top) + 1;
Rect boundsRect;
GetControlBounds (inControl, &boundsRect);
Rect newRect;
newRect.top = boundsRect.top;
newRect.bottom = newRect.top + height;
newRect.left = boundsRect.left;
newRect.right = newRect.left + width;
SetControlBounds (inControl, &newRect);
if (outWidth)
*outWidth = width;
if (outHeight)
*outHeight = height;
#endif
return true;
}
#pragma mark ___AUPropertyControl
bool AUPropertyControl::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event)
{
UInt32 eclass = GetEventClass(event);
UInt32 ekind = GetEventKind(event);
switch (eclass) {
case kEventClassControl:
switch (ekind) {
case kEventControlValueFieldChanged:
HandleControlChange();
return true; // handled
}
}
return false;
}
void AUPropertyControl::RegisterEvents ()
{
#if !__LP64__
EventTypeSpec events[] = {
{ kEventClassControl, kEventControlValueFieldChanged } // N.B. OS X only
};
WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
#endif
}
void AUPropertyControl::EmbedControl (ControlRef theControl)
{
mView->EmbedControl (theControl);
}
WindowRef AUPropertyControl::GetCarbonWindow()
{
return mView->GetCarbonWindow();
}
#pragma mark ___AUVPreset
#if !__LP64__
static CFStringRef kStringFactoryPreset = kAUViewLocalizedStringKey_FactoryPreset;
static bool sAUVPresetLocalized = false;
#endif
AUVPresets::AUVPresets (AUCarbonViewBase* inParentView,
CFArrayRef& inPresets,
Point inLocation,
int nameWidth,
int controlWidth,
ControlFontStyleRec & inFontStyle)
: AUPropertyControl (inParentView),
mPresets (inPresets),
mView (inParentView)
{
#if !__LP64__
Rect r;
// ok we now have an array of factory presets
// get their strings and display them
r.top = inLocation.v; r.bottom = r.top;
r.left = inLocation.h; r.right = r.left;
// localize as necessary
if (!sAUVPresetLocalized) {
CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(kLocalizedStringBundle_AUView);
if (mainBundle) {
kStringFactoryPreset = CFCopyLocalizedStringFromTableInBundle(
kAUViewLocalizedStringKey_FactoryPreset, kLocalizedStringTable_AUView,
mainBundle, CFSTR("FactoryPreset title string"));
sAUVPresetLocalized = true;
}
}
// create localized title string
CFMutableStringRef factoryPresetsTitle = CFStringCreateMutable(NULL, 0);
CFStringAppend(factoryPresetsTitle, kStringFactoryPreset);
CFStringAppend(factoryPresetsTitle, kAUViewUnlocalizedString_TitleSeparator);
ControlRef theControl;
verify_noerr(CreateStaticTextControl(mView->GetCarbonWindow(), &r, factoryPresetsTitle, &inFontStyle, &theControl));
SInt16 width = 0;
AUCarbonViewControl::SizeControlToFit(theControl, &width, &mHeight);
CFRelease(factoryPresetsTitle);
EmbedControl(theControl);
r.top -= 2;
r.left += width + 10;
r.right = r.left;
r.bottom = r.top;
verify_noerr(CreatePopupButtonControl ( mView->GetCarbonWindow(), &r, NULL,
-12345, // DON'T GET MENU FROM RESOURCE mMenuID,!!!
FALSE, // variableWidth,
0, // titleWidth,
0, // titleJustification,
0, // titleStyle,
&mControl));
MenuRef menuRef;
verify_noerr(CreateNewMenu(1, 0, &menuRef));
int numPresets = CFArrayGetCount(mPresets);
for (int i = 0; i < numPresets; ++i)
{
AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i);
verify_noerr(AppendMenuItemTextWithCFString (menuRef, preset->presetName, 0, 0, 0));
}
verify_noerr(SetControlData(mControl, 0, kControlPopupButtonMenuRefTag, sizeof(menuRef), &menuRef));
verify_noerr (SetControlFontStyle (mControl, &inFontStyle));
SetControl32BitMaximum (mControl, numPresets);
// size popup
SInt16 height = 0;
AUCarbonViewControl::SizeControlToFit(mControl, &width, &height);
if (height > mHeight) mHeight = height;
if (mHeight < 0) mHeight = 0;
// find which menu item is the Default preset
UInt32 propertySize = sizeof(AUPreset);
AUPreset defaultPreset;
OSStatus result = AudioUnitGetProperty (mView->GetEditAudioUnit(),
kAudioUnitProperty_PresentPreset,
kAudioUnitScope_Global,
0,
&defaultPreset,
&propertySize);
mPropertyID = kAudioUnitProperty_PresentPreset;
#endif
#ifndef __LP64__
if (result != noErr) { // if the PresentPreset property is not implemented, fall back to the CurrentPreset property
OSStatus result = AudioUnitGetProperty (mView->GetEditAudioUnit(),
kAudioUnitProperty_CurrentPreset,
kAudioUnitScope_Global,
0,
&defaultPreset,
&propertySize);
mPropertyID = kAudioUnitProperty_CurrentPreset;
if (result == noErr)
CFRetain (defaultPreset.presetName);
}
#endif
#if !__LP64__
EmbedControl (mControl);
HandlePropertyChange(defaultPreset);
RegisterEvents();
#endif
}
void AUVPresets::AddInterest (AUEventListenerRef inListener,
void * inObject)
{
AudioUnitEvent e;
e.mEventType = kAudioUnitEvent_PropertyChange;
e.mArgument.mProperty.mAudioUnit = mView->GetEditAudioUnit();
e.mArgument.mProperty.mPropertyID = mPropertyID;
e.mArgument.mProperty.mScope = kAudioUnitScope_Global;
e.mArgument.mProperty.mElement = 0;
AUEventListenerAddEventType(inListener, inObject, &e);
}
void AUVPresets::RemoveInterest (AUEventListenerRef inListener,
void * inObject)
{
AudioUnitEvent e;
e.mEventType = kAudioUnitEvent_PropertyChange;
e.mArgument.mProperty.mAudioUnit = mView->GetEditAudioUnit();
e.mArgument.mProperty.mPropertyID = mPropertyID;
e.mArgument.mProperty.mScope = kAudioUnitScope_Global;
e.mArgument.mProperty.mElement = 0;
AUEventListenerRemoveEventType(inListener, inObject, &e);
}
void AUVPresets::HandleControlChange ()
{
#if !__LP64__
SInt32 i = GetControl32BitValue(mControl);
if (i > 0)
{
AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i-1);
verify_noerr(AudioUnitSetProperty (mView->GetEditAudioUnit(),
mPropertyID, // either currentPreset or PresentPreset depending on which is supported
kAudioUnitScope_Global,
0,
preset,
sizeof(AUPreset)));
// when we change a preset we can't expect the AU to update its state
// as it isn't meant to know that its being viewed!
// so we broadcast a notification to all listeners that all parameters on this AU have changed
AudioUnitParameter changedUnit;
changedUnit.mAudioUnit = mView->GetEditAudioUnit();
changedUnit.mParameterID = kAUParameterListener_AnyParameter;
verify_noerr (AUParameterListenerNotify (NULL, NULL, &changedUnit) );
}
#endif
}
void AUVPresets::HandlePropertyChange(AUPreset &preset)
{
#if !__LP64__
// check to see if the preset is in our menu
int numPresets = CFArrayGetCount(mPresets);
if (preset.presetNumber < 0) {
SetControl32BitValue (mControl, 0); //controls are one-based
} else {
for (SInt32 i = 0; i < numPresets; ++i) {
AUPreset* currPreset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i);
if (preset.presetNumber == currPreset->presetNumber) {
SetControl32BitValue (mControl, ++i); //controls are one-based
break;
}
}
}
if (preset.presetName)
CFRelease (preset.presetName);
#endif
}
bool AUVPresets::HandlePropertyChange (const AudioUnitProperty &inProp)
{
if (inProp.mPropertyID == mPropertyID)
{
UInt32 theSize = sizeof(AUPreset);
AUPreset currentPreset;
OSStatus result = AudioUnitGetProperty(inProp.mAudioUnit,
inProp.mPropertyID,
inProp.mScope,
inProp.mElement, &currentPreset, &theSize);
if (result == noErr) {
#ifndef __LP64__
if (inProp.mPropertyID == kAudioUnitProperty_CurrentPreset && currentPreset.presetName)
CFRetain (currentPreset.presetName);
#endif
HandlePropertyChange(currentPreset);
return true;
}
}
return false;
}

View File

@@ -0,0 +1,230 @@
/*
File: AUCarbonViewControl.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUCarbonViewControl_h__
#define __AUCarbonViewControl_h__
#include <Carbon/Carbon.h>
#include <AudioUnit/AudioUnitCarbonView.h>
#include <AudioToolbox/AudioUnitUtilities.h>
#include "CarbonEventHandler.h"
#include "CAAUParameter.h"
class AUCarbonViewBase;
// ____________________________________________________________________________
// AUCarbonViewControl
// Wrapper for a control that is wired to an AudioUnit parameter.
/*! @class AUCarbonViewControl */
class AUCarbonViewControl : public CarbonEventHandler {
// note that the controls are never disposed; that's managed by the AUCarbonViewBase's
// parent pane which contains all of them ... if we later need to be able to delete
// individual controls on the fly, extra work needed
public:
enum ControlType {
kTypeContinuous, // e.g. slider
kTypeDiscrete, // e.g. pop-up menu
kTypeText
};
AUCarbonViewControl(AUCarbonViewBase *ownerView, AUParameterListenerRef listener, ControlType type, const CAAUParameter &param, ControlRef control);
~AUCarbonViewControl();
/*! @method Bind */
virtual void Bind(); // second-stage construction
/*! @method ControlToParameter */
virtual void ControlToParameter();
/*! @method ParameterToControl */
virtual void ParameterToControl(Float32 newValue);
/*! @method SetValueFract */
virtual void SetValueFract(double value);
/*! @method GetValueFract */
virtual double GetValueFract();
/*! @method SetTextValue */
virtual void SetTextValue(CFStringRef str);
/*! @method GetTextValue */
virtual CFStringRef GetTextValue();
/*! @method SetValue */
virtual void SetValue(long value);
/*! @method GetValue */
virtual long GetValue();
/*! @method GetOwnerView */
AUCarbonViewBase * GetOwnerView() {return mOwnerView;}
/*! @method Update */
void Update (bool inUIThread)
{
if (inUIThread)
ParameterToControl (mParam.GetValue());
else
AUParameterListenerNotify (mListener, this, &mParam);
}
// CarbonEventHandler overrides
/*! @method HandleEvent */
virtual bool HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event);
/*! @method ControlRef */
operator ControlRef() { return mControl; }
/*! @method SizeControlToFit */
static Boolean SizeControlToFit(ControlRef inControl, SInt16 *outWidth = NULL, SInt16 *outHeight = NULL);
/*! @method SliderTrackProc */
static pascal void SliderTrackProc(ControlRef theControl, ControlPartCode partCode);
/*! @method NumericKeyFilterCallback */
static pascal ControlKeyFilterResult NumericKeyFilterCallback(ControlRef theControl, SInt16 *keyCode, SInt16 *charCode,
EventModifiers *modifiers);
protected:
/*! @method ParamInfo */
const AudioUnitParameterInfo &ParamInfo() { return mParam.ParamInfo(); }
/*! @var mOwnerView */
AUCarbonViewBase * mOwnerView;
/*! @var mListener */
AUParameterListenerRef mListener;
/*! @var mType */
ControlType mType;
/*! @var mParam */
CAAUParameter mParam;
/*! @var mControl */
ControlRef mControl;
/*! @method StdKeyFilterCallback */
static pascal ControlKeyFilterResult StdKeyFilterCallback(ControlRef theControl, SInt16 *keyCode, SInt16 *charCode,
EventModifiers *modifiers);
SInt16 mInControlInitialization;
static AUCarbonViewControl* mLastControl;
};
/*! @class AUPropertyControl */
class AUPropertyControl : public CarbonEventHandler {
public:
/*! @ctor AUPropertyControl */
AUPropertyControl (AUCarbonViewBase * inBase) : mControl(0), mView (inBase), mHeight(0) {}
/*! @method HandleEvent */
virtual bool HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event);
/*! @method HandlePropertyChange */
virtual bool HandlePropertyChange (const AudioUnitProperty &inProp) = 0;
/*! @method AddInterest */
virtual void AddInterest (AUEventListenerRef inListener,
void * inObject) = 0;
/*! @method RemoveInterest */
virtual void RemoveInterest (AUEventListenerRef inListener,
void * inObject) = 0;
/*! @method GetHeight */
int GetHeight() { return mHeight;}
protected:
/*! @method HandleControlChange */
virtual void HandleControlChange () = 0;
/*! @method RegisterEvents */
void RegisterEvents ();
/*! @method EmbedControl */
void EmbedControl (ControlRef theControl);
/*! @method GetCarbonWindow */
WindowRef GetCarbonWindow();
/*! @var mControl */
ControlRef mControl;
/*! @var mView */
AUCarbonViewBase* mView;
/*! @var mHeight */
SInt16 mHeight;
};
/*! @class AUVPresets */
class AUVPresets : public AUPropertyControl {
public:
/*! @ctor HandleControlChange */
AUVPresets (AUCarbonViewBase * inBase,
CFArrayRef& inPresets,
Point inLocation,
int nameWidth,
int controlWidth,
ControlFontStyleRec & inFontStyle);
virtual ~AUVPresets () { CFRelease (mPresets); }
/*! @method HandlePropertyChange */
virtual bool HandlePropertyChange (const AudioUnitProperty &inProp);
/*! @method AddInterest */
virtual void AddInterest (AUEventListenerRef inListener,
void * inObject);
/*! @method RemoveInterest */
virtual void RemoveInterest (AUEventListenerRef inListener,
void * inObject);
protected:
/*! @method HandleControlChange */
virtual void HandleControlChange ();
/*! @var mPresets */
CFArrayRef mPresets;
/*! @var mView */
AUCarbonViewBase* mView;
AudioUnitPropertyID mPropertyID;
void HandlePropertyChange(AUPreset &preset);
};
#endif // __AUCarbonViewControl_h__

View File

@@ -0,0 +1,125 @@
/*
File: AUCarbonViewDispatch.cpp
Abstract: AUCarbonViewDispatch.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUCarbonViewBase.h"
// ____________________________________________________________________________
// component dispatch
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif
struct AudioUnitCarbonViewCreateGluePB {
unsigned char componentFlags;
unsigned char componentParamSize;
short componentWhat;
ControlRef* outControl;
const Float32Point* inSize;
const Float32Point* inLocation;
ControlRef inParentControl;
WindowRef inWindow;
AudioUnit inAudioUnit;
AudioUnitCarbonView inView;
};
#if !__LP64__
struct AudioUnitCarbonViewSetEventListenerGluePB {
unsigned char componentFlags;
unsigned char componentParamSize;
short componentWhat;
void* inUserData;
AudioUnitCarbonViewEventListener inCallback;
AudioUnitCarbonView inView;
};
#endif
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif
#define CheckNull(x) if ((x) == NULL) return paramErr;
OSStatus AUCarbonViewBase::ComponentEntryDispatch(ComponentParameters *p, AUCarbonViewBase *This)
{
if (This == NULL) return paramErr;
OSStatus result = noErr;
switch (p->what) {
case kAudioUnitCarbonViewCreateSelect:
{
AudioUnitCarbonViewCreateGluePB *pb = (AudioUnitCarbonViewCreateGluePB *)p;
CheckNull(pb->inAudioUnit);
CheckNull(pb->inWindow);
CheckNull(pb->inParentControl);
CheckNull(pb->inSize);
CheckNull(pb->inLocation);
CheckNull(pb->outControl);
result = This->CreateCarbonView(pb->inAudioUnit, pb->inWindow, pb->inParentControl,
*pb->inLocation, *pb->inSize, *pb->outControl);
}
break;
#if !__LP64__
case kAudioUnitCarbonViewSetEventListenerSelect:
{
AudioUnitCarbonViewSetEventListenerGluePB *pb = (AudioUnitCarbonViewSetEventListenerGluePB *)p;
This->SetEventListener(pb->inCallback, pb->inUserData);
}
break;
#endif
default:
result = ComponentBase::ComponentEntryDispatch(p, This);
break;
}
return result;
}

View File

@@ -0,0 +1,359 @@
/*
File: AUControlGroup.cpp
Abstract: AUControlGroup.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include <Carbon/Carbon.h>
#include "AUCarbonViewBase.h"
#include "AUCarbonViewControl.h"
#include "AUControlGroup.h"
#include "AUViewLocalizedStringKeys.h"
#define kSliderThinDimension 10
#define kLabelAndSliderSpacing 4
#if !__LP64__
static CFStringRef kStringManufacturer = kAUViewLocalizedStringKey_Manufacturer;
static bool sLocalized = false;
#endif
void AUControlGroup::CreateLabelledSlider(
AUCarbonViewBase * auView,
const CAAUParameter & auvp,
const Rect & area,
Point labelSize,
const ControlFontStyleRec & inFontStyle)
{
#if !__LP64__
ControlFontStyleRec fontStyle = inFontStyle;
Rect minValRect, maxValRect, sliderRect;
ControlRef newControl;
int width = area.right - area.left, height = area.bottom - area.top;
CFStringRef cfstr;
int sliderValueMax, sliderValueMin, sliderValueDefault;
AUCarbonViewControl::ControlType sliderType;
bool horizontal = (width > height);
if (horizontal) {
maxValRect.top = minValRect.top = area.top + (height - labelSize.v) / 2;
minValRect.left = area.left;
maxValRect.left = area.right - labelSize.h;
minValRect.bottom = minValRect.top + labelSize.v;
minValRect.right = minValRect.left + labelSize.h;
maxValRect.bottom = maxValRect.top + labelSize.v;
maxValRect.right = maxValRect.left + labelSize.h;
sliderRect.left = minValRect.right + kLabelAndSliderSpacing;
sliderRect.right = maxValRect.left - kLabelAndSliderSpacing;
sliderRect.top = area.top + (height - kSliderThinDimension) / 2;
sliderRect.bottom = sliderRect.top + kSliderThinDimension + 4;
if (auvp.IsIndexedParam ()) {
sliderValueMin = sliderValueDefault = int(auvp.ParamInfo().minValue);
sliderValueMax = int(auvp.ParamInfo().maxValue);
sliderType = AUCarbonViewControl::kTypeDiscrete;
} else {
sliderValueMin = sliderValueDefault = 0;
sliderValueMax = sliderRect.right - sliderRect.left;
sliderType = AUCarbonViewControl::kTypeContinuous;
}
} else {
maxValRect.left = minValRect.left = area.left + (width - labelSize.h) / 2;
maxValRect.top = area.top;
minValRect.top = area.bottom - labelSize.v;
minValRect.bottom = minValRect.top + labelSize.v;
minValRect.right = minValRect.left + labelSize.h;
maxValRect.bottom = maxValRect.top + labelSize.v;
maxValRect.right = maxValRect.left + labelSize.h;
sliderRect.left = area.left + (width - kSliderThinDimension) / 2;
sliderRect.right = sliderRect.left + kSliderThinDimension + 4;
sliderRect.top = maxValRect.bottom + kLabelAndSliderSpacing;
sliderRect.bottom = minValRect.top - kLabelAndSliderSpacing;
if (auvp.IsIndexedParam ()) {
sliderValueMin = sliderValueDefault = int(auvp.ParamInfo().minValue);
sliderValueMax = int(auvp.ParamInfo().maxValue);
sliderType = AUCarbonViewControl::kTypeDiscrete;
} else {
sliderValueMin = sliderValueDefault = 0;
sliderValueMax = sliderRect.bottom - sliderRect.top;
sliderType = AUCarbonViewControl::kTypeContinuous;
}
}
// minimum value label
if (labelSize.v > 0 && labelSize.h > 0) {
// check to see if the minimum value has a label
cfstr = auvp.GetStringFromValueCopy(&auvp.ParamInfo().minValue);
fontStyle.just = horizontal ? teFlushRight : teCenter;
verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &minValRect, cfstr, &fontStyle, &newControl));
CFRelease(cfstr);
verify_noerr(auView->EmbedControl(newControl));
// maximum value label
cfstr = auvp.GetStringFromValueCopy(&auvp.ParamInfo().maxValue);
fontStyle.just = horizontal ? teFlushLeft : teCenter;
verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &maxValRect, cfstr, &fontStyle, &newControl));
CFRelease(cfstr);
verify_noerr(auView->EmbedControl(newControl));
}
// slider
verify_noerr(CreateSliderControl(auView->GetCarbonWindow(), &sliderRect, sliderValueDefault, sliderValueMin, sliderValueMax, kControlSliderDoesNotPoint, 0, true, AUCarbonViewControl::SliderTrackProc, &newControl));
ControlSize small = kControlSizeSmall;
SetControlData(newControl, kControlEntireControl, kControlSizeTag, sizeof(ControlSize), &small);
auView->AddCarbonControl(sliderType, auvp, newControl);
#endif
}
void AUControlGroup::CreateLabelledSliderAndEditText(
AUCarbonViewBase * auView,
const CAAUParameter & auvp,
const Rect & area,
Point labelSize,
Point editTextSize,
const ControlFontStyleRec & inFontStyle)
{
#if !__LP64__
ControlFontStyleRec fontStyle = inFontStyle;
Rect sliderArea, textArea;
ControlRef newControl;
int width = area.right - area.left, height = area.bottom - area.top;
bool horizontal = (width > height);
sliderArea = area;
textArea = area;
if (horizontal) {
textArea.left = area.right - editTextSize.h;
// provide a large text box if param is generic and its values have strings...
if (auvp.ValuesHaveStrings() && (auvp.ParamInfo().unit == kAudioUnitParameterUnit_Generic))
{
textArea.right += 30;
}
sliderArea.right = textArea.left - kLabelAndSliderSpacing;
textArea.top = area.top + (height - editTextSize.v) / 2;
textArea.bottom = textArea.top + editTextSize.v;
} else {
textArea.top = area.bottom - editTextSize.v;
sliderArea.bottom = textArea.top - kLabelAndSliderSpacing;
textArea.left = area.left + (width - editTextSize.h) / 2;
textArea.right = textArea.left + editTextSize.h;
}
CreateLabelledSlider(auView, auvp, sliderArea, labelSize, fontStyle);
verify_noerr(CreateEditUnicodeTextControl(auView->GetCarbonWindow(), &textArea, CFSTR(""), false,
&fontStyle, &newControl));
auView->AddCarbonControl(AUCarbonViewControl::kTypeText, auvp, newControl);
#endif
}
void AUControlGroup::CreatePopupMenu (AUCarbonViewBase * auView,
const CAAUParameter & auvp,
const Rect & area,
const ControlFontStyleRec & inFontStyle,
const bool inSizeToFit)
{
#if !__LP64__
ControlRef thePopUp;
verify_noerr(CreatePopupButtonControl (auView->GetCarbonWindow(), &area, NULL,
-12345, // DON'T GET MENU FROM RESOURCE mMenuID
FALSE, // variableWidth,
0, // titleWidth,
0, // titleJustification,
0, // titleStyle,
&thePopUp));
ControlSize small = kControlSizeSmall;
SetControlData(thePopUp, kControlEntireControl, kControlSizeTag, sizeof(ControlSize), &small);
MenuRef menuRef;
verify_noerr(CreateNewMenu( 1, 0, &menuRef));
for (int i = 0; i < auvp.GetNumIndexedParams(); ++i) {
verify_noerr(AppendMenuItemTextWithCFString (menuRef, auvp.GetParamName(i), kMenuItemAttrIgnoreMeta, 0, 0));
}
verify_noerr(SetControlData(thePopUp, 0, kControlPopupButtonMenuRefTag, sizeof(menuRef), &menuRef));
SetControl32BitMaximum(thePopUp, auvp.GetNumIndexedParams());
verify_noerr (SetControlFontStyle (thePopUp, &inFontStyle));
if (inSizeToFit) {
AUCarbonViewControl::SizeControlToFit(thePopUp);
}
auView->AddCarbonControl(AUCarbonViewControl::kTypeDiscrete, auvp, thePopUp);
#endif
}
void AUControlGroup::AddAUInfo ( AUCarbonViewBase * auView,
const Point & inLocation,
const SInt16 inRightOffset,
const SInt16 inTotalWidth)
{
#if !__LP64__
// get component info
ComponentDescription desc;
Handle h1 = NewHandleClear(4);
OSStatus err = GetComponentInfo ((Component)auView->GetEditAudioUnit(), &desc, h1, 0, 0);
if (err == noErr) {
// Get the manufacturer's name... look for the ':' character convention
HLock(h1);
char* ptr1 = *h1;
int len = *ptr1++;
char* displayStr = 0;
for (int i = 0; i < len; ++i) {
if (ptr1[i] == ':') { // found the name
ptr1[i++] = 0;
displayStr = ptr1;
break;
}
}
// localize as necessary:
if (!sLocalized) {
CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(kLocalizedStringBundle_AUView);
if (mainBundle) {
kStringManufacturer = CFCopyLocalizedStringFromTableInBundle(
kAUViewLocalizedStringKey_Manufacturer, kLocalizedStringTable_AUView,
mainBundle, CFSTR("Manufacturer title string"));
sLocalized = true;
}
}
// display strings
ControlRef newControl;
Rect r;
r.top = SInt16(inLocation.v); r.bottom = SInt16(inLocation.v) + 16;
ControlFontStyleRec fontStyle;
fontStyle.flags = kControlUseFontMask | kControlUseJustMask;
fontStyle.font = kControlFontSmallBoldSystemFont;
// display manufacturer string
if (displayStr) {
CFMutableStringRef mfrstring = CFStringCreateMutable(NULL, 0);
CFStringAppend(mfrstring, kStringManufacturer); // "Manufacturer"
CFStringAppend(mfrstring, kAUViewUnlocalizedString_TitleSeparator);
// "Manufacturer: "
CFStringRef mfrname = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingUTF8);
if (mfrname) {
CFStringAppend(mfrstring, mfrname); // "Manufacturer: MFRName"
CFRelease (mfrname);
}
r.left = inLocation.h + inRightOffset;
r.right = inLocation.h + inTotalWidth - 28;
fontStyle.just = teFlushRight;
verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &r, mfrstring, &fontStyle, &newControl));
verify_noerr(auView->EmbedControl(newControl));
CFRelease (mfrstring);
//move displayStr ptr past the manu, to the name
// we move the characters down an index, because the handle doesn't have any room
// at the end for the \0
int i = strlen(displayStr), j = 0;
while (displayStr[++i] == ' ' && i < len)
;
while (i < len)
displayStr[j++] = displayStr[i++];
displayStr[j] = 0;
} else {
displayStr = ptr1;
int i = 0, j = 0;
do {
displayStr[j] = displayStr[i];
++j; ++i;
} while (i < len);
displayStr[j] = 0;
}
// display AudioUnit string
r.left = inLocation.h; r.right = r.left + inRightOffset;
fontStyle.just = 0;
CFMutableStringRef cfstr = CFStringCreateMutable(NULL, 0);
CFStringAppend(cfstr, kAUViewLocalizedStringKey_AudioUnit); // "Audio Unit"
CFStringAppend(cfstr, kAUViewUnlocalizedString_TitleSeparator);
// "Audio Unit: "
CFStringRef auname = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingUTF8);
CFStringAppend(cfstr, auname); // "Audio Unit: AUName"
CFRelease (auname);
verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &r, cfstr, &fontStyle, &newControl));
// size text control correctly
Boolean bValue = false;
SetControlData(newControl, kControlEntireControl, 'stim' /* kControlStaticTextIsMultilineTag */, sizeof(Boolean), &bValue);
SInt16 baseLineOffset;
Rect bestRect;
err = GetBestControlRect(newControl, &bestRect, &baseLineOffset);
if (err == noErr)
{
int width = (bestRect.right - bestRect.left) + 1;
int height = (bestRect.bottom - bestRect.top) + 1;
SizeControl (newControl, width, height);
}
verify_noerr(auView->EmbedControl(newControl));
CFRelease (cfstr);
}
DisposeHandle (h1);
#endif
}

View File

@@ -0,0 +1,90 @@
/*
File: AUControlGroup.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUControlGroup_h__
#define __AUControlGroup_h__
#include <Carbon/Carbon.h>
class AUCarbonViewBase;
class CAAUParameter;
// Utility class to create clusters of controls related to a single parameter
/*! @class AUControlGroup */
class AUControlGroup {
public:
/*! @method CreateLabelledSlider */
static void CreateLabelledSlider( AUCarbonViewBase * auView,
const CAAUParameter & auvp,
const Rect & area,
Point labelSize,
const ControlFontStyleRec & fontStyle);
/*! @method CreateLabelledSliderAndEditText */
static void CreateLabelledSliderAndEditText(
AUCarbonViewBase * auView,
const CAAUParameter & auvp,
const Rect & area,
Point labelSize,
Point editTextSize,
const ControlFontStyleRec & fontStyle);
/*! @method CreatePopupMenu */
static void CreatePopupMenu ( AUCarbonViewBase * auView,
const CAAUParameter & auvp,
const Rect & area,
const ControlFontStyleRec & inFontStyle,
const bool inSizeToFit = false);
/*! @method AddAUInfo */
static void AddAUInfo ( AUCarbonViewBase * auView,
const Point & inLocation,
const SInt16 inRightOffset,
const SInt16 inTotalWidth);
};
#endif // __AUControlGroup_h__

View File

@@ -0,0 +1,90 @@
/*
File: CarbonEventHandler.cpp
Abstract: CarbonEventHandler.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CarbonEventHandler.h"
static pascal OSStatus TheEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
{
CarbonEventHandler *handler = (CarbonEventHandler *)inUserData;
if (handler->HandleEvent(inHandlerRef, inEvent))
return noErr;
else return eventNotHandledErr;
}
CarbonEventHandler::CarbonEventHandler() :
mHandlers(NULL)
{
}
CarbonEventHandler::~CarbonEventHandler()
{
if (mHandlers != NULL) {
int count = static_cast<int>(CFDictionaryGetCount(mHandlers));
EventHandlerRef *theHandlers = (EventHandlerRef*) malloc(count * sizeof(EventHandlerRef));
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)theHandlers);
for (int i = 0; i < count; i++)
RemoveEventHandler(theHandlers[i]);
CFDictionaryRemoveAllValues(mHandlers);
CFRelease (mHandlers);
free(theHandlers);
}
}
void CarbonEventHandler::WantEventTypes(EventTargetRef target, UInt32 inNumTypes, const EventTypeSpec *inList)
{
if (mHandlers == NULL)
mHandlers = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
EventHandlerRef handler;
if (CFDictionaryGetValueIfPresent (mHandlers, target, (const void **)&handler)) // if there is already a handler for the target, add the type
verify_noerr(AddEventTypesToHandler(handler, inNumTypes, inList));
else {
verify_noerr(InstallEventHandler(target, TheEventHandler, inNumTypes, inList, this, &handler));
CFDictionaryAddValue(mHandlers, target, handler);
}
}

View File

@@ -0,0 +1,71 @@
/*
File: CarbonEventHandler.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __CarbonEventHandler_h__
#define __CarbonEventHandler_h__
#include <Carbon/Carbon.h>
/*! @class CarbonEventHandler */
class CarbonEventHandler {
public:
/*! @ctor CarbonEventHandler */
CarbonEventHandler();
/*! @dtor ~CarbonEventHandler */
virtual ~CarbonEventHandler();
/*! @method WantEventTypes */
virtual void WantEventTypes(EventTargetRef target, UInt32 inNumTypes, const EventTypeSpec *inList);
/*! @method HandleEvent */
virtual bool HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event) = 0;
protected:
/*! @var mHandlers */
CFMutableDictionaryRef mHandlers;
};
#endif // __CarbonEventHandler_h__

View File

@@ -0,0 +1,843 @@
/*
File: AUInstrumentBase.cpp
Abstract: AUInstrumentBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUInstrumentBase.h"
#include "AUMIDIDefs.h"
#if DEBUG
#define DEBUG_PRINT 0
#define DEBUG_PRINT_NOTE 0
#define DEBUG_PRINT_RENDER 0
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const UInt32 kEventQueueSize = 1024;
AUInstrumentBase::AUInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups,
UInt32 numParts)
: MusicDeviceBase(inInstance, numInputs, numOutputs, numGroups),
mAbsoluteSampleFrame(0),
mEventQueue(kEventQueueSize),
mNumNotes(0),
mNumActiveNotes(0),
mMaxActiveNotes(0),
mNotes(0),
mNoteSize(0),
mInitNumPartEls(numParts)
{
#if DEBUG_PRINT
printf("new AUInstrumentBase\n");
#endif
mFreeNotes.mState = kNoteState_Free;
SetWantsRenderThreadID(true);
}
AUInstrumentBase::~AUInstrumentBase()
{
#if DEBUG_PRINT
printf("delete AUInstrumentBase\n");
#endif
}
AUElement * AUInstrumentBase::CreateElement(AudioUnitScope inScope, AudioUnitElement element)
{
switch (inScope)
{
case kAudioUnitScope_Group:
return new SynthGroupElement(this, element, new MidiControls);
case kAudioUnitScope_Part:
return new SynthPartElement (this, element);
}
return MusicDeviceBase::CreateElement(inScope, element);
}
void AUInstrumentBase::CreateExtendedElements()
{
Parts().Initialize(this, kAudioUnitScope_Part, mInitNumPartEls);
}
AUScope * AUInstrumentBase::GetScopeExtended (AudioUnitScope inScope)
{
if (inScope == kAudioUnitScope_Part)
return &mPartScope;
return NULL;
}
void AUInstrumentBase::SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteDataSize)
{
#if DEBUG_PRINT_NOTE
printf("AUInstrumentBase::SetNotes %d %d %p %d\n", inNumNotes, inMaxActiveNotes, inNotes, inNoteDataSize);
#endif
mNumNotes = inNumNotes;
mMaxActiveNotes = inMaxActiveNotes;
mNoteSize = inNoteDataSize;
mNotes = inNotes;
for (UInt32 i=0; i<mNumNotes; ++i)
{
SynthNote *note = GetNote(i);
note->Reset();
mFreeNotes.AddNote(note);
}
}
UInt32 AUInstrumentBase::CountActiveNotes()
{
// debugging tool.
UInt32 sum = 0;
for (UInt32 i=0; i<mNumNotes; ++i)
{
SynthNote *note = GetNote(i);
if (note->GetState() <= kNoteState_Released)
sum++;
}
return sum;
}
void AUInstrumentBase::AddFreeNote(SynthNote* inNote)
{
// Fast-released notes are already considered inactive and have already decr'd the active count
if (inNote->GetState() < kNoteState_FastReleased) {
DecNumActiveNotes();
}
#if DEBUG_PRINT_NOTE
else {
printf("AUInstrumentBase::AddFreeNote: adding fast-released note %p\n", inNote);
}
printf("AUInstrumentBase::AddFreeNote (%p) mNumActiveNotes %lu\n", inNote, mNumActiveNotes);
#endif
mFreeNotes.AddNote(inNote);
}
OSStatus AUInstrumentBase::Initialize()
{
/*
TO DO:
Currently ValidFormat will check and validate that the num channels is not being
changed if the AU doesn't support the SupportedNumChannels property - which is correct
What needs to happen here is that IFF the AU does support this property, (ie, the AU
can be configured to have different num channels than its original configuration) then
the state of the AU at Initialization needs to be validated.
This is work still to be done - see AUEffectBase for the kind of logic that needs to be applied here
*/
// override to call SetNotes
mNoteIDCounter = 128; // reset this every time we initialise
mAbsoluteSampleFrame = 0;
return noErr;
}
void AUInstrumentBase::Cleanup()
{
mFreeNotes.Empty();
}
OSStatus AUInstrumentBase::Reset( AudioUnitScope inScope,
AudioUnitElement inElement)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::Reset\n");
#endif
if (inScope == kAudioUnitScope_Global)
{
// kill all notes..
mFreeNotes.Empty();
for (UInt32 i=0; i<mNumNotes; ++i)
{
SynthNote *note = GetNote(i);
if (note->IsSounding())
note->Kill(0);
note->ListRemove();
mFreeNotes.AddNote(note);
}
mNumActiveNotes = 0;
mAbsoluteSampleFrame = 0;
// empty lists.
UInt32 numGroups = Groups().GetNumberOfElements();
for (UInt32 j = 0; j < numGroups; ++j)
{
SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
group->Reset();
}
}
return MusicDeviceBase::Reset(inScope, inElement);
}
void AUInstrumentBase::PerformEvents(const AudioTimeStamp& inTimeStamp)
{
#if DEBUG_PRINT_RENDER
printf("AUInstrumentBase::PerformEvents\n");
#endif
SynthEvent *event;
SynthGroupElement *group;
while ((event = mEventQueue.ReadItem()) != NULL)
{
#if DEBUG_PRINT_RENDER
printf("event %08X %d\n", event, event->GetEventType());
#endif
switch(event->GetEventType())
{
case SynthEvent::kEventType_NoteOn :
RealTimeStartNote(GetElForGroupID (event->GetGroupID()), event->GetNoteID(),
event->GetOffsetSampleFrame(), *event->GetParams());
break;
case SynthEvent::kEventType_NoteOff :
RealTimeStopNote(event->GetGroupID(), event->GetNoteID(),
event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SustainOn :
group = GetElForGroupID (event->GetGroupID());
group->SustainOn(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SustainOff :
group = GetElForGroupID (event->GetGroupID());
group->SustainOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SostenutoOn :
group = GetElForGroupID (event->GetGroupID());
group->SostenutoOn(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_SostenutoOff :
group = GetElForGroupID (event->GetGroupID());
group->SostenutoOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_AllNotesOff :
group = GetElForGroupID (event->GetGroupID());
group->AllNotesOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_AllSoundOff :
group = GetElForGroupID (event->GetGroupID());
group->AllSoundOff(event->GetOffsetSampleFrame());
break;
case SynthEvent::kEventType_ResetAllControllers :
group = GetElForGroupID (event->GetGroupID());
group->ResetAllControllers(event->GetOffsetSampleFrame());
break;
}
mEventQueue.AdvanceReadPtr();
}
}
OSStatus AUInstrumentBase::Render( AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames)
{
PerformEvents(inTimeStamp);
AUScope &outputs = Outputs();
UInt32 numOutputs = outputs.GetNumberOfElements();
for (UInt32 j = 0; j < numOutputs; ++j)
{
GetOutput(j)->PrepareBuffer(inNumberFrames); // AUBase::DoRenderBus() only does this for the first output element
AudioBufferList& bufferList = GetOutput(j)->GetBufferList();
for (UInt32 k = 0; k < bufferList.mNumberBuffers; ++k)
{
memset(bufferList.mBuffers[k].mData, 0, bufferList.mBuffers[k].mDataByteSize);
}
}
UInt32 numGroups = Groups().GetNumberOfElements();
for (UInt32 j = 0; j < numGroups; ++j)
{
SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
OSStatus err = group->Render((SInt64)inTimeStamp.mSampleTime, inNumberFrames, outputs);
if (err) return err;
}
mAbsoluteSampleFrame += inNumberFrames;
return noErr;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUInstrumentBase::ValidFormat
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool AUInstrumentBase::ValidFormat( AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inNewFormat)
{
// if the AU supports this, then we should just let this go through to the Init call
if (SupportedNumChannels (NULL))
return MusicDeviceBase::ValidFormat(inScope, inElement, inNewFormat);
bool isGood = MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat);
if (!isGood) return false;
// if we get to here, then the basic criteria is that the
// num channels cannot change on an existing bus
AUIOElement *el = GetIOElement (inScope, inElement);
return (el->GetStreamFormat().NumberChannels() == inNewFormat.NumberChannels());
}
bool AUInstrumentBase::StreamFormatWritable( AudioUnitScope scope,
AudioUnitElement element)
{
return IsInitialized() ? false : true;
}
OSStatus AUInstrumentBase::RealTimeStartNote( SynthGroupElement *inGroup,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
return noErr;
}
SynthPartElement * AUInstrumentBase::GetPartElement (AudioUnitElement inPartElement)
{
AUScope & parts = Parts();
unsigned int numEls = parts.GetNumberOfElements();
for (unsigned int i = 0; i < numEls; ++i) {
SynthPartElement* el = reinterpret_cast<SynthPartElement*>(parts.GetElement(i));
if (el->GetIndex() == inPartElement) {
return el;
}
}
return NULL;
}
SynthGroupElement * AUInstrumentBase::GetElForGroupID (MusicDeviceGroupID inGroupID)
{
AUScope & groups = Groups();
unsigned int numEls = groups.GetNumberOfElements();
SynthGroupElement* unassignedEl = NULL;
for (unsigned int i = 0; i < numEls; ++i) {
SynthGroupElement* el = reinterpret_cast<SynthGroupElement*>(groups.GetElement(i));
if (el->GroupID() == inGroupID)
return el;
if (el->GroupID() == SynthGroupElement::kUnassignedGroup) {
unassignedEl = el;
break; // we fill this up from the start of the group scope vector
}
}
if (unassignedEl) {
unassignedEl->SetGroupID(inGroupID);
return unassignedEl;
}
throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
}
OSStatus AUInstrumentBase::RealTimeStopNote(
MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::RealTimeStopNote ch %d id %d\n", inGroupID, inNoteInstanceID);
#endif
SynthGroupElement *gp = (inGroupID == kMusicNoteEvent_Unused
? GetElForNoteID (inNoteInstanceID)
: GetElForGroupID(inGroupID));
if (gp)
{
gp->NoteOff (inNoteInstanceID, inOffsetSampleFrame);
}
return noErr;
}
SynthGroupElement * AUInstrumentBase::GetElForNoteID (NoteInstanceID inNoteID)
{
#if DEBUG_PRINT
printf("GetElForNoteID id %u\n", inNoteID);
#endif
AUScope & groups = Groups();
unsigned int numEls = groups.GetNumberOfElements();
for (unsigned int i = 0; i < numEls; ++i) {
SynthGroupElement* el = reinterpret_cast<SynthGroupElement*>(groups.GetElement(i));
if (el->GetNote(inNoteID) != NULL) // searches for any note state
return el;
}
throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
}
OSStatus AUInstrumentBase::StartNote( MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
OSStatus err = noErr;
NoteInstanceID noteID;
if (outNoteInstanceID) {
noteID = NextNoteID();
*outNoteInstanceID = noteID;
} else
noteID = (UInt32)inParams.mPitch;
#if DEBUG_PRINT
printf("AUInstrumentBase::StartNote ch %u, key %u, offset %u\n", inGroupID, (unsigned) inParams.mPitch, inOffsetSampleFrame);
#endif
if (InRenderThread ())
{
err = RealTimeStartNote(
GetElForGroupID(inGroupID),
noteID,
inOffsetSampleFrame,
inParams);
}
else
{
SynthEvent *event = mEventQueue.WriteItem();
if (!event) return -1; // queue full
event->Set(
SynthEvent::kEventType_NoteOn,
inGroupID,
noteID,
inOffsetSampleFrame,
&inParams
);
mEventQueue.AdvanceWritePtr();
}
return err;
}
OSStatus AUInstrumentBase::StopNote( MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::StopNote ch %u, id %u, offset %u\n", (unsigned)inGroupID, (unsigned)inNoteInstanceID, inOffsetSampleFrame);
#endif
OSStatus err = noErr;
if (InRenderThread ())
{
err = RealTimeStopNote(
inGroupID,
inNoteInstanceID,
inOffsetSampleFrame);
}
else
{
SynthEvent *event = mEventQueue.WriteItem();
if (!event) return -1; // queue full
event->Set(
SynthEvent::kEventType_NoteOff,
inGroupID,
inNoteInstanceID,
inOffsetSampleFrame,
NULL
);
mEventQueue.AdvanceWritePtr();
}
return err;
}
OSStatus AUInstrumentBase::SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame)
{
if (InRenderThread ())
{
SynthGroupElement *group = GetElForGroupID(inGroupID);
if (!group)
return kAudioUnitErr_InvalidElement;
switch (inEventType)
{
case SynthEvent::kEventType_SustainOn :
group->SustainOn(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_SustainOff :
group->SustainOff(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_SostenutoOn :
group->SostenutoOn(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_SostenutoOff :
group->SostenutoOff(inOffsetSampleFrame);
break;
case SynthEvent::kEventType_AllNotesOff :
group->AllNotesOff(inOffsetSampleFrame);
mNumActiveNotes = CountActiveNotes();
break;
case SynthEvent::kEventType_AllSoundOff :
group->AllSoundOff(inOffsetSampleFrame);
mNumActiveNotes = CountActiveNotes();
break;
case SynthEvent::kEventType_ResetAllControllers :
group->ResetAllControllers(inOffsetSampleFrame);
break;
}
}
else
{
SynthEvent *event = mEventQueue.WriteItem();
if (!event) return -1; // queue full
event->Set(inEventType, inGroupID, 0, 0, NULL);
mEventQueue.AdvanceWritePtr();
}
return noErr;
}
OSStatus AUInstrumentBase::HandleControlChange( UInt8 inChannel,
UInt8 inController,
UInt8 inValue,
UInt32 inStartFrame)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::HandleControlChange ch %u ctlr: %u val: %u frm: %u\n", inChannel, inController, inValue, inStartFrame);
#endif
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(inController, inValue);
}
else
return kAudioUnitErr_InvalidElement;
switch (inController)
{
case kMidiController_Sustain :
if (inValue >= 64)
SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOn, inStartFrame);
else
SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOff, inStartFrame);
break;
case kMidiController_Sostenuto :
if (inValue >= 64)
SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOn, inStartFrame);
else
SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOff, inStartFrame);
break;
case kMidiController_OmniModeOff:
case kMidiController_OmniModeOn:
case kMidiController_MonoModeOn:
case kMidiController_MonoModeOff:
HandleAllSoundOff(inChannel);
break;
}
return noErr;
}
OSStatus AUInstrumentBase::HandlePitchWheel( UInt8 inChannel,
UInt8 inPitch1, // LSB
UInt8 inPitch2, // MSB
UInt32 inStartFrame)
{
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(kMidiMessage_PitchWheel, (inPitch2 << 7) | inPitch1);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandleChannelPressure(UInt8 inChannel,
UInt8 inValue,
UInt32 inStartFrame)
{
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(kMidiMessage_ChannelPressure, inValue);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandleProgramChange( UInt8 inChannel,
UInt8 inValue)
{
#if DEBUG_PRINT
printf("AUInstrumentBase::HandleProgramChange %u %u\n", inChannel, inValue);
#endif
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
gp->ChannelMessage(kMidiMessage_ProgramChange, inValue);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandlePolyPressure( UInt8 inChannel,
UInt8 inKey,
UInt8 inValue,
UInt32 inStartFrame)
{
SynthGroupElement *gp = GetElForGroupID(inChannel);
if (gp)
{
// Combine key and value into single argument. UGLY!
gp->ChannelMessage(kMidiMessage_PolyPressure, (inKey << 7) | inValue);
return noErr;
}
else
return kAudioUnitErr_InvalidElement;
}
OSStatus AUInstrumentBase::HandleResetAllControllers( UInt8 inChannel)
{
return SendPedalEvent (inChannel, SynthEvent::kEventType_ResetAllControllers, 0);
}
OSStatus AUInstrumentBase::HandleAllNotesOff( UInt8 inChannel)
{
return SendPedalEvent (inChannel, SynthEvent::kEventType_AllNotesOff, 0);
}
OSStatus AUInstrumentBase::HandleAllSoundOff( UInt8 inChannel)
{
return SendPedalEvent (inChannel, SynthEvent::kEventType_AllSoundOff, 0);
}
SynthNote* AUInstrumentBase::GetAFreeNote(UInt32 inFrame)
{
#if DEBUG_PRINT_NOTE
printf("AUInstrumentBase::GetAFreeNote: %lu available\n", mFreeNotes.Length());
#endif
SynthNote *note = mFreeNotes.mHead;
if (note)
{
mFreeNotes.RemoveNote(note);
return note;
}
return VoiceStealing(inFrame, true);
}
SynthNote* AUInstrumentBase::VoiceStealing(UInt32 inFrame, bool inKillIt)
{
#if DEBUG_PRINT_NOTE
printf("AUInstrumentBase::VoiceStealing\n");
#endif
// free list was empty so we need to kill a note.
UInt32 startState = inKillIt ? kNoteState_FastReleased : kNoteState_Released;
for (UInt32 i = startState; i <= startState; --i)
{
#if DEBUG_PRINT_NOTE
printf(" checking state %d...\n", i);
#endif
UInt32 numGroups = Groups().GetNumberOfElements();
for (UInt32 j = 0; j < numGroups; ++j)
{
SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j);
#if DEBUG_PRINT_NOTE
printf("\tsteal group %d size %d\n", j, group->mNoteList[i].Length());
#endif
if (group->mNoteList[i].NotEmpty()) {
#if DEBUG_PRINT_NOTE
printf("\t-- not empty\n");
#endif
SynthNote *note = group->mNoteList[i].FindMostQuietNote();
if (inKillIt) {
#if DEBUG_PRINT_NOTE
printf("\t--=== KILL ===---\n");
#endif
note->Kill(inFrame);
group->mNoteList[i].RemoveNote(note);
if (i != kNoteState_FastReleased)
DecNumActiveNotes();
return note;
} else {
#if DEBUG_PRINT_NOTE
printf("\t--=== FAST RELEASE ===---\n");
#endif
group->mNoteList[i].RemoveNote(note);
note->FastRelease(inFrame);
group->mNoteList[kNoteState_FastReleased].AddNote(note);
DecNumActiveNotes(); // kNoteState_FastReleased counts as inactive for voice stealing purposes.
return NULL;
}
}
}
}
#if DEBUG_PRINT_NOTE
printf("no notes to steal????\n");
#endif
return NULL; // It should be impossible to get here. It means there were no notes to kill in any state.
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
AUMonotimbralInstrumentBase::AUMonotimbralInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups,
UInt32 numParts)
: AUInstrumentBase(inInstance, numInputs, numOutputs, numGroups, numParts)
{
}
OSStatus AUMonotimbralInstrumentBase::RealTimeStartNote(
SynthGroupElement *inGroup,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
#if DEBUG_PRINT_RENDER
printf("AUMonotimbralInstrumentBase::RealTimeStartNote %d\n", inNoteInstanceID);
#endif
if (NumActiveNotes() + 1 > MaxActiveNotes())
{
VoiceStealing(inOffsetSampleFrame, false);
}
SynthNote *note = GetAFreeNote(inOffsetSampleFrame);
if (!note) return -1;
SynthPartElement *part = GetPartElement (0); // Only one part for monotimbral
IncNumActiveNotes();
inGroup->NoteOn(note, part, inNoteInstanceID, inOffsetSampleFrame, inParams);
return noErr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
OSStatus AUMultitimbralInstrumentBase::GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
OSStatus result = noErr;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_PartGroup:
if (inScope != kAudioUnitScope_Part) return kAudioUnitErr_InvalidScope;
outDataSize = sizeof(UInt32);
outWritable = true;
break;
#endif
default:
result = AUInstrumentBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
return result;
}
OSStatus AUMultitimbralInstrumentBase::GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
OSStatus result = noErr;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_PartGroup:
if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
// ??
return -1; //unimpl
break;
#endif
default:
result = AUInstrumentBase::GetProperty (inID, inScope, inElement, outData);
}
return result;
}
OSStatus AUMultitimbralInstrumentBase::SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
OSStatus result = noErr;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_PartGroup:
if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope;
// ??
return -1; //unimpl
break;
#endif
default:
result = MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,269 @@
/*
File: AUInstrumentBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUInstrumentBase__
#define __AUInstrumentBase__
#include <vector>
#include <stdexcept>
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudio.h>
#include <libkern/OSAtomic.h>
#include "MusicDeviceBase.h"
#include "LockFreeFIFO.h"
#include "SynthEvent.h"
#include "SynthNote.h"
#include "SynthElement.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef LockFreeFIFOWithFree<SynthEvent> SynthEventQueue;
class AUInstrumentBase : public MusicDeviceBase
{
public:
AUInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups = 16,
UInt32 numParts = 1);
virtual ~AUInstrumentBase();
virtual OSStatus Initialize();
/*! @method Parts */
AUScope & Parts() { return mPartScope; }
/*! @method GetPart */
AUElement * GetPart( AudioUnitElement inElement)
{
return mPartScope.SafeGetElement(inElement);
}
virtual AUScope * GetScopeExtended (AudioUnitScope inScope);
virtual AUElement * CreateElement( AudioUnitScope inScope,
AudioUnitElement inElement);
virtual void CreateExtendedElements();
virtual void Cleanup();
virtual OSStatus Reset( AudioUnitScope inScope,
AudioUnitElement inElement);
virtual bool ValidFormat( AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inNewFormat);
virtual bool StreamFormatWritable( AudioUnitScope scope,
AudioUnitElement element);
virtual bool CanScheduleParameters() const { return false; }
virtual OSStatus Render( AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames);
virtual OSStatus StartNote( MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams);
virtual OSStatus StopNote( MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame);
virtual OSStatus RealTimeStartNote( SynthGroupElement *inGroup,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams);
virtual OSStatus RealTimeStopNote( MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame);
virtual OSStatus HandleControlChange( UInt8 inChannel,
UInt8 inController,
UInt8 inValue,
UInt32 inStartFrame);
virtual OSStatus HandlePitchWheel( UInt8 inChannel,
UInt8 inPitch1,
UInt8 inPitch2,
UInt32 inStartFrame);
virtual OSStatus HandleChannelPressure( UInt8 inChannel,
UInt8 inValue,
UInt32 inStartFrame);
virtual OSStatus HandleProgramChange( UInt8 inChannel,
UInt8 inValue);
virtual OSStatus HandlePolyPressure( UInt8 inChannel,
UInt8 inKey,
UInt8 inValue,
UInt32 inStartFrame);
virtual OSStatus HandleResetAllControllers( UInt8 inChannel);
virtual OSStatus HandleAllNotesOff( UInt8 inChannel);
virtual OSStatus HandleAllSoundOff( UInt8 inChannel);
SynthNote* GetNote(UInt32 inIndex)
{
if (!mNotes)
throw std::runtime_error("no notes");
return (SynthNote*)((char*)mNotes + inIndex * mNoteSize);
}
SynthNote* GetAFreeNote(UInt32 inFrame);
void AddFreeNote(SynthNote* inNote);
friend class SynthGroupElement;
protected:
UInt32 NextNoteID() { return OSAtomicIncrement32((int32_t *)&mNoteIDCounter); }
// call SetNotes in your Initialize() method to give the base class your note structures and to set the maximum
// number of active notes. inNoteData should be an array of size inMaxActiveNotes.
void SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteSize);
void PerformEvents( const AudioTimeStamp & inTimeStamp);
OSStatus SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame);
virtual SynthNote* VoiceStealing(UInt32 inFrame, bool inKillIt);
UInt32 MaxActiveNotes() const { return mMaxActiveNotes; }
UInt32 NumActiveNotes() const { return mNumActiveNotes; }
void IncNumActiveNotes() { ++mNumActiveNotes; }
void DecNumActiveNotes() { --mNumActiveNotes; }
UInt32 CountActiveNotes();
SynthPartElement * GetPartElement (AudioUnitElement inPartElement);
// this call throws if there's no assigned element for the group ID
virtual SynthGroupElement * GetElForGroupID (MusicDeviceGroupID inGroupID);
virtual SynthGroupElement * GetElForNoteID (NoteInstanceID inNoteID);
SInt64 mAbsoluteSampleFrame;
private:
SInt32 mNoteIDCounter;
SynthEventQueue mEventQueue;
UInt32 mNumNotes;
UInt32 mNumActiveNotes;
UInt32 mMaxActiveNotes;
SynthNote* mNotes;
SynthNoteList mFreeNotes;
UInt32 mNoteSize;
AUScope mPartScope;
const UInt32 mInitNumPartEls;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
class AUMonotimbralInstrumentBase : public AUInstrumentBase
{
public:
AUMonotimbralInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups = 16,
UInt32 numParts = 1);
virtual OSStatus RealTimeStartNote( SynthGroupElement *inGroup,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this is a work in progress! The mono-timbral one is finished though!
class AUMultitimbralInstrumentBase : public AUInstrumentBase
{
public:
AUMultitimbralInstrumentBase(
AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups,
UInt32 numParts);
virtual OSStatus GetPropertyInfo( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable);
virtual OSStatus GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual OSStatus SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize);
private:
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif

View File

@@ -0,0 +1,168 @@
/*
File: LockFreeFIFO.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include <libkern/OSAtomic.h>
template <class ITEM>
class LockFreeFIFOWithFree
{
LockFreeFIFOWithFree(); // private, unimplemented.
public:
LockFreeFIFOWithFree(UInt32 inMaxSize)
: mReadIndex(0), mWriteIndex(0), mFreeIndex(0)
{
//assert(IsPowerOfTwo(inMaxSize));
mItems = new ITEM[inMaxSize];
mMask = inMaxSize - 1;
}
~LockFreeFIFOWithFree()
{
delete [] mItems;
}
void Reset()
{
FreeItems();
mReadIndex = 0;
mWriteIndex = 0;
mFreeIndex = 0;
}
ITEM* WriteItem()
{
//printf("WriteItem %d %d\n", mReadIndex, mWriteIndex);
FreeItems(); // free items on the write thread.
int32_t nextWriteIndex = (mWriteIndex + 1) & mMask;
if (nextWriteIndex == mFreeIndex) return NULL;
return &mItems[mWriteIndex];
}
ITEM* ReadItem()
{
//printf("ReadItem %d %d\n", mReadIndex, mWriteIndex);
if (mReadIndex == mWriteIndex) return NULL;
return &mItems[mReadIndex];
}
void AdvanceWritePtr() { OSAtomicCompareAndSwap32(mWriteIndex, (mWriteIndex + 1) & mMask, &mWriteIndex); }
void AdvanceReadPtr() { OSAtomicCompareAndSwap32(mReadIndex, (mReadIndex + 1) & mMask, &mReadIndex); }
private:
ITEM* FreeItem()
{
if (mFreeIndex == mReadIndex) return NULL;
return &mItems[mFreeIndex];
}
void AdvanceFreePtr() { OSAtomicCompareAndSwap32(mFreeIndex, (mFreeIndex + 1) & mMask, &mFreeIndex); }
void FreeItems()
{
ITEM* item;
while ((item = FreeItem()) != NULL)
{
item->Free();
AdvanceFreePtr();
}
}
volatile int32_t mReadIndex, mWriteIndex, mFreeIndex;
int32_t mMask;
ITEM *mItems;
};
// Same as above but no free.
template <class ITEM>
class LockFreeFIFO
{
LockFreeFIFO(); // private, unimplemented.
public:
LockFreeFIFO(UInt32 inMaxSize)
: mReadIndex(0), mWriteIndex(0)
{
//assert(IsPowerOfTwo(inMaxSize));
mItems = new ITEM[inMaxSize];
mMask = inMaxSize - 1;
}
~LockFreeFIFO()
{
delete [] mItems;
}
void Reset()
{
mReadIndex = 0;
mWriteIndex = 0;
}
ITEM* WriteItem()
{
int32_t nextWriteIndex = (mWriteIndex + 1) & mMask;
if (nextWriteIndex == mReadIndex) return NULL;
return &mItems[mWriteIndex];
}
ITEM* ReadItem()
{
if (mReadIndex == mWriteIndex) return NULL;
return &mItems[mReadIndex];
}
// the CompareAndSwap will always succeed. We use CompareAndSwap because it calls the PowerPC sync instruction,
// plus any processor bug workarounds for various CPUs.
void AdvanceWritePtr() { OSAtomicCompareAndSwap32(mWriteIndex, (mWriteIndex + 1) & mMask, &mWriteIndex); }
void AdvanceReadPtr() { OSAtomicCompareAndSwap32(mReadIndex, (mReadIndex + 1) & mMask, &mReadIndex); }
private:
volatile int32_t mReadIndex, mWriteIndex;
int32_t mMask;
ITEM *mItems;
};

View File

@@ -0,0 +1,92 @@
/*
File: MIDIControlHandler.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __MIDICONTROLHANDLER_H__
#define __MIDICONTROLHANDLER_H__
#include <CoreAudio/CoreAudio.h>
/*! Abstract interface base class for classes which handle all incoming MIDI data */
class MIDIControlHandler
{
public:
virtual ~MIDIControlHandler() {}
virtual void Reset() = 0; //! Restore all state to defaults
virtual bool SetProgramChange(UInt16 inProgram) = 0;
virtual bool SetPitchWheel(UInt16 inValue) = 0;
virtual bool SetChannelPressure(UInt8 inValue) = 0;
virtual bool SetPolyPressure(UInt8 inKey, UInt8 inValue) = 0;
virtual bool SetController(UInt8 inControllerNumber, UInt8 inValue) = 0;
virtual bool SetSysex(void *inSysexMsg) = 0;
virtual float GetPitchBend() const = 0;
/*! Default controller values. These represent MSB values unless indicated in the name */
enum
{
kDefault_Midpoint = 0x40, //! Used for all center-null-point controllers
kDefault_Volume = 100,
kDefault_Pan = kDefault_Midpoint,
kDefault_ModWheel = 0,
kDefault_Pitch = kDefault_Midpoint,
kDefault_Expression = 0x7f,
kDefault_ChannelPressure = 0,
kDefault_ReverbSend = 40,
kDefault_ChorusSend = 0,
kDefault_RPN_LSB = 0x7f,
kDefault_RPN_MSB = 0x7f,
kDefault_PitchBendRange = 2,
kDefault_FineTuning = kDefault_Midpoint,
kDefault_CoarseTuning = kDefault_Midpoint,
kDefault_ModDepthRange = 0,
kDefault_ModDepthRangeLSB = kDefault_Midpoint
};
};
#endif // __MIDICONTROLHANDLER_H__

View File

@@ -0,0 +1,419 @@
/*
File: SynthElement.cpp
Abstract: SynthElement.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "SynthElement.h"
#include "AUInstrumentBase.h"
#include "AUMIDIDefs.h"
#undef DEBUG_PRINT
#define DEBUG_PRINT 0
#define DEBUG_PRINT_NOTE 0
#define DEBUG_PRINT_RENDER 0
////////////////////////////////////////////////////////////////////////////////////////////////////////////
MidiControls::MidiControls()
{
Reset();
}
void MidiControls::Reset()
{
memset(mControls, 0, sizeof(mControls));
memset(mPolyPressure, 0, sizeof(mPolyPressure));
mMonoPressure = 0;
mProgramChange = 0;
mPitchBend = 0;
mActiveRPN = 0;
mActiveNRPN = 0;
mActiveRPValue = 0;
mActiveNRPValue = 0;
mControls[kMidiController_Pan] = 64;
mControls[kMidiController_Expression] = 127;
mPitchBendDepth = 24 << 7;
mFPitchBendDepth = 24.0f;
mFPitchBend = 0.0f;
}
SynthElement::SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement)
: AUElement(audioUnit), mIndex(inElement)
{
}
SynthElement::~SynthElement()
{
}
SynthGroupElement::SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement, MIDIControlHandler *inHandler)
: SynthElement(audioUnit, inElement),
mCurrentAbsoluteFrame(-1),
mMidiControlHandler(inHandler),
mSustainIsOn(false), mSostenutoIsOn(false), mOutputBus(0), mGroupID(kUnassignedGroup)
{
for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i)
mNoteList[i].mState = (SynthNoteState) i;
}
SynthGroupElement::~SynthGroupElement()
{
delete mMidiControlHandler;
}
void SynthGroupElement::SetGroupID (MusicDeviceGroupID inGroup)
{
// can't re-assign a group once its been assigned
if (mGroupID != kUnassignedGroup) throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement);
mGroupID = inGroup;
}
void SynthGroupElement::Reset()
{
#if DEBUG_PRINT
printf("SynthGroupElement::Reset\n");
#endif
mMidiControlHandler->Reset();
for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i)
mNoteList[i].Empty();
}
SynthPartElement::SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement)
: SynthElement(audioUnit, inElement)
{
}
// Return the SynthNote with the given inNoteID, if found. If unreleasedOnly is true, only look for
// attacked and sostenutoed notes, otherwise search all states. Return state of found note via outNoteState.
SynthNote *SynthGroupElement::GetNote(NoteInstanceID inNoteID, bool unreleasedOnly, UInt32 *outNoteState)
{
#if DEBUG_PRINT_RENDER
printf("SynthGroupElement::GetNote %d, unreleased = %d\n", inNoteID, unreleasedOnly);
#endif
const UInt32 lastNoteState = unreleasedOnly ?
(mSostenutoIsOn ? kNoteState_Sostenutoed : kNoteState_Attacked)
: kNoteState_Released;
SynthNote *note = NULL;
// Search for notes in each successive state
for (UInt32 noteState = kNoteState_Attacked; noteState <= lastNoteState; ++noteState)
{
if (outNoteState) *outNoteState = noteState; // even if we find nothing
note = mNoteList[noteState].mHead;
while (note && note->mNoteID != inNoteID)
{
#if DEBUG_PRINT_RENDER
printf(" checking %p id: %d\n", note, note->mNoteID);
#endif
note = note->mNext;
}
if (note)
{
#if DEBUG_PRINT_RENDER
printf(" found %p\n", note);
#endif
break;
}
}
return note;
}
void SynthGroupElement::NoteOn(SynthNote *note,
SynthPartElement *part,
NoteInstanceID inNoteID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
#if DEBUG_PRINT_NOTE
printf("SynthGroupElement::NoteOn %d\n", inNoteID);
#endif
// TODO: CONSIDER FIXING this to not need to initialize mCurrentAbsoluteFrame to -1.
UInt64 absoluteFrame = (mCurrentAbsoluteFrame == -1) ? inOffsetSampleFrame : mCurrentAbsoluteFrame + inOffsetSampleFrame;
if (note->AttackNote(part, this, inNoteID, absoluteFrame, inOffsetSampleFrame, inParams)) {
mNoteList[kNoteState_Attacked].AddNote(note);
}
}
void SynthGroupElement::NoteOff(NoteInstanceID inNoteID, UInt32 inFrame)
{
#if DEBUG_PRINT_NOTE
printf("SynthGroupElement::NoteOff %d\n", inNoteID);
#endif
UInt32 noteState = kNoteState_Attacked;
SynthNote *note = GetNote(inNoteID, true, &noteState); // asking for unreleased only
if (note)
{
#if DEBUG_PRINT_NOTE
printf(" old note state: %d\n", note->mState);
#endif
if (noteState == kNoteState_Attacked)
{
mNoteList[noteState].RemoveNote(note);
if (mSustainIsOn) {
mNoteList[kNoteState_ReleasedButSustained].AddNote(note);
} else {
note->Release(inFrame);
mNoteList[kNoteState_Released].AddNote(note);
}
#if DEBUG_PRINT_NOTE
printf(" new note state: %d\n", note->mState);
#endif
}
else /* if (noteState == kNoteState_Sostenutoed) */
{
mNoteList[kNoteState_Sostenutoed].RemoveNote(note);
mNoteList[kNoteState_ReleasedButSostenutoed].AddNote(note);
}
}
}
void SynthGroupElement::NoteEnded(SynthNote *inNote, UInt32 inFrame)
{
#if DEBUG_PRINT_NOTE
printf("SynthGroupElement::NoteEnded: id %d state %d\n", inNote->mNoteID, inNote->mState);
#endif
if (inNote->IsSounding()) {
SynthNoteList *list = &mNoteList[inNote->GetState()];
list->RemoveNote(inNote);
}
GetAUInstrument()->AddFreeNote(inNote);
}
void SynthGroupElement::NoteFastReleased(SynthNote *inNote)
{
#if DEBUG_PRINT_NOTE
printf("SynthGroupElement::NoteFastReleased id %d state %d\n", inNote->mNoteID, inNote->mState);
#endif
if (inNote->IsActive()) {
mNoteList[inNote->GetState()].RemoveNote(inNote);
GetAUInstrument()->DecNumActiveNotes();
mNoteList[kNoteState_FastReleased].AddNote(inNote);
}
else {
Assert(true, "ASSERT FAILED: Attempting to fast-release non-active note");
}
}
bool SynthGroupElement::ChannelMessage(UInt16 controllerID, UInt16 inValue)
{
bool handled = true;
#if DEBUG_PRINT
printf("SynthGroupElement::ChannelMessage(0x%x, %u)\n", controllerID, inValue);
#endif
// Sustain and sostenuto are "pedal events", and are handled during render cycle
if (controllerID <= kMidiController_RPN_MSB && controllerID != kMidiController_Sustain && controllerID != kMidiController_Sostenuto)
handled = mMidiControlHandler->SetController(controllerID, UInt8(inValue));
else
{
switch (controllerID)
{
case kMidiMessage_ProgramChange:
handled = mMidiControlHandler->SetProgramChange(inValue);
break;
case kMidiMessage_PitchWheel:
handled = mMidiControlHandler->SetPitchWheel(inValue);
break;
case kMidiMessage_ChannelPressure:
#if DEBUG_PRINT
printf("SynthGroupElement::ChannelMessage: Channel Pressure %u\n", inValue);
#endif
handled = mMidiControlHandler->SetChannelPressure(UInt8(inValue));
break;
case kMidiMessage_PolyPressure:
{ UInt8 inKey = inValue >> 7;
UInt8 val = inValue & 0x7f;
handled = mMidiControlHandler->SetPolyPressure(inKey, val);
break;
}
default:
handled = false;
break;
}
}
return handled;
}
void SynthGroupElement::SostenutoOn(UInt32 inFrame)
{
#if DEBUG_PRINT
printf("SynthGroupElement::SostenutoOn\n");
#endif
if (!mSostenutoIsOn) {
mMidiControlHandler->SetController(kMidiController_Sostenuto, 127);
mSostenutoIsOn = true;
mNoteList[kNoteState_Sostenutoed].TransferAllFrom(&mNoteList[kNoteState_Attacked], inFrame);
}
}
void SynthGroupElement::SostenutoOff(UInt32 inFrame)
{
#if DEBUG_PRINT
printf("SynthGroupElement::SostenutoOff\n");
#endif
if (mSostenutoIsOn) {
mMidiControlHandler->SetController(kMidiController_Sostenuto, 0);
mSostenutoIsOn = false;
mNoteList[kNoteState_Attacked].TransferAllFrom(&mNoteList[kNoteState_Sostenutoed], inFrame);
if (mSustainIsOn)
mNoteList[kNoteState_ReleasedButSustained].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSostenutoed], inFrame);
else
mNoteList[kNoteState_Released].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSostenutoed], inFrame);
}
}
void SynthGroupElement::SustainOn(UInt32 inFrame)
{
#if DEBUG_PRINT
// printf("SynthGroupElement::SustainOn\n");
#endif
if (!mSustainIsOn) {
mMidiControlHandler->SetController(kMidiController_Sustain, 127);
mSustainIsOn = true;
}
}
void SynthGroupElement::SustainOff(UInt32 inFrame)
{
#if DEBUG_PRINT
// printf("SynthGroupElement::SustainOff\n");
#endif
if (mSustainIsOn) {
mMidiControlHandler->SetController(kMidiController_Sustain, 0);
mSustainIsOn = false;
mNoteList[kNoteState_Released].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSustained], inFrame);
}
}
void SynthGroupElement::AllNotesOff(UInt32 inFrame)
{
#if DEBUG_PRINT
printf("SynthGroupElement::AllNotesOff\n");
#endif
SynthNote *note;
for (UInt32 i=0 ; i<=kNoteState_Sostenutoed; ++i)
{
UInt32 newState = (i == kNoteState_Attacked) ?
kNoteState_Released : kNoteState_ReleasedButSostenutoed;
note = mNoteList[i].mHead;
while (note)
{
SynthNote *nextNote = note->mNext;
mNoteList[i].RemoveNote(note);
note->Release(inFrame);
mNoteList[newState].AddNote(note);
note = nextNote;
}
}
}
void SynthGroupElement::AllSoundOff(UInt32 inFrame)
{
#if DEBUG_PRINT
printf("SynthGroupElement::AllSoundOff\n");
#endif
SynthNote *note;
for (UInt32 i=0 ; i<kNumberOfActiveNoteStates; ++i)
{
note = mNoteList[i].mHead;
while (note)
{
SynthNote *nextNote = note->mNext;
mNoteList[i].RemoveNote(note);
note->FastRelease(inFrame);
mNoteList[kNoteState_FastReleased].AddNote(note);
GetAUInstrument()->DecNumActiveNotes();
note = nextNote;
}
}
}
void SynthGroupElement::ResetAllControllers(UInt32 inFrame)
{
#if DEBUG_PRINT
printf("SynthGroupElement::ResetAllControllers\n");
#endif
mMidiControlHandler->Reset();
}
OSStatus SynthGroupElement::Render(SInt64 inAbsoluteSampleFrame, UInt32 inNumberFrames, AUScope &outputs)
{
// Avoid duplicate calls at same sample offset
if (inAbsoluteSampleFrame != mCurrentAbsoluteFrame)
{
mCurrentAbsoluteFrame = inAbsoluteSampleFrame;
AudioBufferList* buffArray[16];
UInt32 numOutputs = outputs.GetNumberOfElements();
for (UInt32 outBus = 0; outBus < numOutputs && outBus < 16; ++outBus)
{
buffArray[outBus] = &GetAudioUnit()->GetOutput(outBus)->GetBufferList();
}
for (UInt32 i=0 ; i<kNumberOfSoundingNoteStates; ++i)
{
SynthNote *note = mNoteList[i].mHead;
while (note)
{
#if DEBUG_PRINT_RENDER
printf("SynthGroupElement::Render: state %d, note %p\n", i, note);
#endif
SynthNote *nextNote = note->mNext;
OSStatus err = note->Render(inAbsoluteSampleFrame, inNumberFrames, buffArray, numOutputs);
if (err) return err;
note = nextNote;
}
}
}
return noErr;
}

View File

@@ -0,0 +1,227 @@
/*
File: SynthElement.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __SynthElement__
#define __SynthElement__
#include <AudioUnit/AudioUnit.h>
#include "MusicDeviceBase.h"
#include "SynthNoteList.h"
#include "MIDIControlHandler.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////
class AUInstrumentBase;
class SynthElement : public AUElement
{
public:
SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement);
virtual ~SynthElement();
UInt32 GetIndex() const { return mIndex; }
AUInstrumentBase* GetAUInstrument() { return (AUInstrumentBase*)GetAudioUnit(); }
private:
UInt32 mIndex;
};
class MidiControls : public MIDIControlHandler
{
enum { kMaxControls = 128 };
public:
MidiControls();
virtual ~MidiControls() {}
virtual void Reset();
virtual bool SetProgramChange(UInt16 inProgram) { mProgramChange = inProgram; return true; }
virtual bool SetPitchWheel(UInt16 inValue) {
mPitchBend = inValue;
mFPitchBend = (float)(((SInt16)mPitchBend - 8192) / 8192.);
return true;
}
virtual bool SetChannelPressure(UInt8 inValue) { mMonoPressure = inValue; return true; }
virtual bool SetPolyPressure(UInt8 inKey, UInt8 inValue) {
mPolyPressure[inKey] = inValue;
return true;
}
virtual bool SetController(UInt8 inControllerNumber, UInt8 inValue) {
if (inControllerNumber < kMaxControls) {
mControls[inControllerNumber] = inValue;
return true;
}
return false;
}
virtual bool SetSysex(void *inSysexMsg) { return false; }
virtual float GetPitchBend() const { return mFPitchBend * mFPitchBendDepth; }
SInt16 GetHiResControl(UInt32 inIndex) const
{
return ((mControls[inIndex] & 127) << 7) | (mControls[inIndex + 32] & 127);
}
float GetControl(UInt32 inIndex) const
{
if (inIndex < 32) {
return (float)(mControls[inIndex] + (mControls[inIndex + 32] / 127.));
} else {
return (float)mControls[inIndex];
}
}
private:
UInt8 mControls[128];
UInt8 mPolyPressure[128];
UInt8 mMonoPressure;
UInt8 mProgramChange;
UInt16 mPitchBend;
UInt16 mActiveRPN;
UInt16 mActiveNRPN;
UInt16 mActiveRPValue;
UInt16 mActiveNRPValue;
UInt16 mPitchBendDepth;
float mFPitchBendDepth;
float mFPitchBend;
void SetHiResControl(UInt32 inIndex, UInt8 inMSB, UInt8 inLSB)
{
mControls[inIndex] = inMSB;
mControls[inIndex + 32] = inLSB;
}
};
class SynthGroupElement : public SynthElement
{
public:
enum {
kUnassignedGroup = 0xFFFFFFFF
};
SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement, MIDIControlHandler *inHandler);
virtual ~SynthGroupElement();
virtual void NoteOn(SynthNote *note, SynthPartElement *part, NoteInstanceID inNoteID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams &inParams);
virtual void NoteOff(NoteInstanceID inNoteID, UInt32 inOffsetSampleFrame);
void SustainOn(UInt32 inFrame);
void SustainOff(UInt32 inFrame);
void SostenutoOn(UInt32 inFrame);
void SostenutoOff(UInt32 inFrame);
void NoteEnded(SynthNote *inNote, UInt32 inFrame);
void NoteFastReleased(SynthNote *inNote);
virtual bool ChannelMessage(UInt16 controlID, UInt16 controlValue);
virtual void AllNotesOff(UInt32 inFrame);
virtual void AllSoundOff(UInt32 inFrame);
void ResetAllControllers(UInt32 inFrame);
SynthNote * GetNote(NoteInstanceID inNoteID, bool unreleasedOnly=false, UInt32 *outNoteState=NULL);
void Reset();
virtual OSStatus Render(SInt64 inAbsoluteSampleFrame, UInt32 inNumberFrames, AUScope &outputs);
float GetPitchBend() const { return mMidiControlHandler->GetPitchBend(); }
SInt64 GetCurrentAbsoluteFrame() const { return mCurrentAbsoluteFrame; }
MusicDeviceGroupID GroupID () const { return mGroupID; }
virtual void SetGroupID (MusicDeviceGroupID inGroup);
MIDIControlHandler * GetMIDIControlHandler() const { return mMidiControlHandler; }
protected:
SInt64 mCurrentAbsoluteFrame;
SynthNoteList mNoteList[kNumberOfSoundingNoteStates];
MIDIControlHandler *mMidiControlHandler;
private:
friend class AUInstrumentBase;
friend class AUMonotimbralInstrumentBase;
friend class AUMultitimbralInstrumentBase;
bool mSustainIsOn;
bool mSostenutoIsOn;
UInt32 mOutputBus;
MusicDeviceGroupID mGroupID;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SynthKeyZone
{
UInt8 mLoNote;
UInt8 mHiNote;
UInt8 mLoVelocity;
UInt8 mHiVelocity;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const UInt32 kUnlimitedPolyphony = 0xFFFFFFFF;
class SynthPartElement : public SynthElement
{
public:
SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement);
UInt32 GetGroupIndex() const { return mGroupIndex; }
bool InRange(Float32 inNote, Float32 inVelocity);
UInt32 GetMaxPolyphony() const { return mMaxPolyphony; }
void SetMaxPolyphony(UInt32 inMaxPolyphony) { mMaxPolyphony = inMaxPolyphony; }
private:
UInt32 mGroupIndex;
UInt32 mPatchIndex;
UInt32 mMaxPolyphony;
SynthKeyZone mKeyZone;
};
#endif

View File

@@ -0,0 +1,145 @@
/*
File: SynthEvent.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
/* You can either fill in code here or remove this and create or add new files. */
#ifndef __SynthEvent__
#define __SynthEvent__
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudio.h>
#include "MusicDeviceBase.h"
#include <stdexcept>
////////////////////////////////////////////////////////////////////////////////////////////////////////////
class SynthEvent
{
public:
enum {
kEventType_NoteOn = 1,
kEventType_NoteOff = 2,
kEventType_SustainOn = 3,
kEventType_SustainOff = 4,
kEventType_SostenutoOn = 5,
kEventType_SostenutoOff = 6,
kEventType_AllNotesOff = 7,
kEventType_AllSoundOff = 8,
kEventType_ResetAllControllers = 9
};
SynthEvent() {}
~SynthEvent() {}
void Set(
UInt32 inEventType,
MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams* inNoteParams
)
{
mEventType = inEventType;
mGroupID = inGroupID;
mNoteID = inNoteID;
mOffsetSampleFrame = inOffsetSampleFrame;
if (inNoteParams)
{
UInt32 paramSize = offsetof(MusicDeviceNoteParams, mControls) + (inNoteParams->argCount-2)*sizeof(NoteParamsControlValue);
mNoteParams = inNoteParams->argCount > 3
? (MusicDeviceNoteParams*)malloc(paramSize)
: &mSmallNoteParams;
memcpy(mNoteParams, inNoteParams, paramSize);
}
else
mNoteParams = NULL;
}
void Free()
{
if (mNoteParams)
{
if (mNoteParams->argCount > 3)
free(mNoteParams);
mNoteParams = NULL;
}
}
UInt32 GetEventType() const { return mEventType; }
MusicDeviceGroupID GetGroupID() const { return mGroupID; }
NoteInstanceID GetNoteID() const { return mNoteID; }
UInt32 GetOffsetSampleFrame() const { return mOffsetSampleFrame; }
MusicDeviceNoteParams* GetParams() const { return mNoteParams; }
UInt32 GetArgCount() const { return mNoteParams->argCount; }
UInt32 NumberParameters() const { return mNoteParams->argCount - 2; }
Float32 GetNote() const { return mNoteParams->mPitch; }
Float32 GetVelocity() const { return mNoteParams->mVelocity; }
NoteParamsControlValue GetParameter(UInt32 inIndex) const
{
if (inIndex >= NumberParameters())
throw std::runtime_error("index out of range");
return mNoteParams->mControls[inIndex];
}
private:
UInt32 mEventType;
MusicDeviceGroupID mGroupID;
NoteInstanceID mNoteID;
UInt32 mOffsetSampleFrame;
MusicDeviceNoteParams* mNoteParams;
MusicDeviceNoteParams mSmallNoteParams; // inline a small one to eliminate malloc for the simple case.
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif

View File

@@ -0,0 +1,140 @@
/*
File: SynthNote.cpp
Abstract: SynthNote.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "SynthNote.h"
#include "SynthElement.h"
#include "AUInstrumentBase.h"
bool SynthNote::AttackNote(
SynthPartElement * inPart,
SynthGroupElement * inGroup,
NoteInstanceID inNoteID,
UInt64 inAbsoluteSampleFrame,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams)
{
#if DEBUG_PRINT
printf("SynthNote::AttackNote %lu %lu abs frame %llu rel frame %lu\n", (UInt32)inGroup->GroupID(), (UInt32)inNoteID, inAbsoluteSampleFrame, inOffsetSampleFrame);
#endif
mPart = inPart;
mGroup = inGroup;
mNoteID = inNoteID;
mAbsoluteStartFrame = inAbsoluteSampleFrame;
mRelativeStartFrame = inOffsetSampleFrame;
mRelativeReleaseFrame = -1;
mRelativeKillFrame = -1;
mPitch = inParams.mPitch;
mVelocity = inParams.mVelocity;
return Attack(inParams);
}
void SynthNote::Reset()
{
mPart = 0;
mGroup = 0;
mAbsoluteStartFrame = 0;
mRelativeStartFrame = 0;
mRelativeReleaseFrame = 0;
mRelativeKillFrame = 0;
}
void SynthNote::Kill(UInt32 inFrame)
{
mRelativeKillFrame = inFrame;
}
void SynthNote::Release(UInt32 inFrame)
{
mRelativeReleaseFrame = inFrame;
}
void SynthNote::FastRelease(UInt32 inFrame)
{
mRelativeReleaseFrame = inFrame;
}
double SynthNote::TuningA() const
{
return 440.0;
}
double SynthNote::Frequency()
{
return TuningA() * pow(2., (mPitch - 69. + GetPitchBend()) / 12.);
}
double SynthNote::SampleRate()
{
return GetAudioUnit()->GetOutput(0)->GetStreamFormat().mSampleRate;
}
AUInstrumentBase* SynthNote::GetAudioUnit() const
{
return (AUInstrumentBase*)mGroup->GetAudioUnit();
}
Float32 SynthNote::GetGlobalParameter(AudioUnitParameterID inParamID) const
{
return mGroup->GetAudioUnit()->Globals()->GetParameter(inParamID);
}
void SynthNote::NoteEnded(UInt32 inFrame)
{
mGroup->NoteEnded(this, inFrame);
mNoteID = 0xFFFFFFFF;
}
float SynthNote::GetPitchBend() const
{
return mGroup->GetPitchBend();
}

View File

@@ -0,0 +1,187 @@
/*
File: SynthNote.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __SynthNote__
#define __SynthNote__
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudio.h>
#include "MusicDeviceBase.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum SynthNoteState {
kNoteState_Attacked = 0,
kNoteState_Sostenutoed = 1,
kNoteState_ReleasedButSostenutoed = 2,
kNoteState_ReleasedButSustained = 3,
kNoteState_Released = 4,
kNoteState_FastReleased = 5,
kNoteState_Free = 6,
kNumberOfActiveNoteStates = 5,
kNumberOfSoundingNoteStates = 6,
kNumberOfNoteStates = 7,
kNoteState_Unset = kNumberOfNoteStates
};
/*
This table describes the state transitions for SynthNotes
EVENT CURRENT STATE NEW STATE
note on free attacked
note off attacked (and sustain on) released but sustained
note off attacked released
note off sostenutoed released but sostenutoed
sustain on -- no changes --
sustain off released but sustained released
sostenuto on attacked sostenutoed
sostenuto off sostenutoed attacked
sostenuto off released but sostenutoed (and sustain on) released but sustained
sostenuto off released but sostenutoed released
end of note any state free
soft voice stealing any state fast released
hard voice stealing any state free
soft voice stealing happens when there is a note on event and NumActiveNotes > MaxActiveNotes
hard voice stealing happens when there is a note on event and NumActiveNotes == NumNotes (no free notes)
voice stealing removes the quietest note in the highest numbered state that has sounding notes.
*/
class SynthGroupElement;
class SynthPartElement;
class AUInstrumentBase;
struct SynthNote
{
SynthNote() :
mPrev(0), mNext(0), mPart(0), mGroup(0),
mNoteID(0xffffffff),
mState(kNoteState_Unset),
mAbsoluteStartFrame(0),
mRelativeStartFrame(0),
mRelativeReleaseFrame(-1),
mRelativeKillFrame(-1),
mPitch(0.0f),
mVelocity(0.0f)
{
}
virtual ~SynthNote() {}
virtual void Reset();
//! Returns true if active note resulted from this call, otherwise false
virtual bool AttackNote(
SynthPartElement * inPart,
SynthGroupElement * inGroup,
NoteInstanceID inNoteID,
UInt64 inAbsoluteSampleFrame,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams &inParams
);
virtual OSStatus Render(UInt64 inAbsoluteSampleFrame, UInt32 inNumFrames, AudioBufferList** inBufferList, UInt32 inOutBusCount) = 0;
//! Returns true if active note resulted from this call, otherwise false
virtual bool Attack(const MusicDeviceNoteParams &inParams) = 0;
virtual void Kill(UInt32 inFrame); // voice is being stolen.
virtual void Release(UInt32 inFrame);
virtual void FastRelease(UInt32 inFrame);
virtual Float32 Amplitude() = 0; // used for finding quietest note for voice stealing.
virtual void NoteEnded(UInt32 inFrame);
SynthGroupElement* GetGroup() const { return mGroup; }
SynthPartElement* GetPart() const { return mPart; }
AUInstrumentBase* GetAudioUnit() const;
Float32 GetGlobalParameter(AudioUnitParameterID inParamID) const;
NoteInstanceID GetNoteID() const { return mNoteID; }
SynthNoteState GetState() const { return mState; }
UInt8 GetMidiKey() const { return (UInt8) mPitch; }
UInt8 GetMidiVelocity() const { return (UInt8) mVelocity; }
Boolean IsSounding() const { return mState < kNumberOfSoundingNoteStates; }
Boolean IsActive() const { return mState < kNumberOfActiveNoteStates; }
UInt64 GetAbsoluteStartFrame() const { return mAbsoluteStartFrame; }
SInt32 GetRelativeStartFrame() const { return mRelativeStartFrame; }
SInt32 GetRelativeReleaseFrame() const { return mRelativeReleaseFrame; }
SInt32 GetRelativeKillFrame() const { return mRelativeKillFrame; }
void ListRemove() { mPrev = mNext = 0; } // only use when lists will be reset.
float GetPitchBend() const;
double TuningA() const;
Float32 GetPitch() const { return mPitch; } // returns raw pitch from MusicDeviceNoteParams
virtual double Frequency(); // returns the frequency of note + pitch bend.
virtual double SampleRate();
// linked list pointers
SynthNote *mPrev;
SynthNote *mNext;
friend class SynthGroupElement;
friend struct SynthNoteList;
protected:
void SetState(SynthNoteState inState) { mState = inState; }
private:
SynthPartElement* mPart;
SynthGroupElement* mGroup;
NoteInstanceID mNoteID;
SynthNoteState mState;
UInt64 mAbsoluteStartFrame;
SInt32 mRelativeStartFrame;
SInt32 mRelativeReleaseFrame;
SInt32 mRelativeKillFrame;
Float32 mPitch;
Float32 mVelocity;
};
#endif

View File

@@ -0,0 +1,93 @@
/*
File: SynthNoteList.cpp
Abstract: SynthNoteList.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "SynthNoteList.h"
#include <stdexcept>
void SynthNoteList::SanityCheck() const
{
if (mState >= kNoteState_Unset) {
throw std::runtime_error("SanityCheck: mState is bad");
}
if (mHead == NULL) {
if (mTail != NULL)
throw std::runtime_error("SanityCheck: mHead is NULL but not mTail");
return;
}
if (mTail == NULL) {
throw std::runtime_error("SanityCheck: mTail is NULL but not mHead");
}
if (mHead->mPrev) {
throw std::runtime_error("SanityCheck: mHead has a mPrev");
}
if (mTail->mNext) {
throw std::runtime_error("SanityCheck: mTail has a mNext");
}
SynthNote *note = mHead;
while (note)
{
if (note->mState != mState)
throw std::runtime_error("SanityCheck: note in wrong state");
if (note->mNext) {
if (note->mNext->mPrev != note)
throw std::runtime_error("SanityCheck: bad link 1");
} else {
if (mTail != note)
throw std::runtime_error("SanityCheck: note->mNext is nil, but mTail != note");
}
if (note->mPrev) {
if (note->mPrev->mNext != note)
throw std::runtime_error("SanityCheck: bad link 2");
} else {
if (mHead != note)
throw std::runtime_error("SanityCheck: note->mPrev is nil, but mHead != note");
}
note = note->mNext;
}
}

View File

@@ -0,0 +1,232 @@
/*
File: SynthNoteList.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __SynthNoteList__
#define __SynthNoteList__
#include "SynthNote.h"
#if DEBUG
#ifndef DEBUG_PRINT
#define DEBUG_PRINT 0
#endif
#define USE_SANITY_CHECK 0
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SynthNoteList
{
SynthNoteList() : mState(kNoteState_Unset), mHead(0), mTail(0) {}
bool NotEmpty() const { return mHead != NULL; }
bool IsEmpty() const { return mHead == NULL; }
void Empty() {
#if USE_SANITY_CHECK
SanityCheck();
#endif
mHead = mTail = NULL;
}
UInt32 Length() const {
#if USE_SANITY_CHECK
SanityCheck();
#endif
UInt32 length = 0;
for (SynthNote* note = mHead; note; note = note->mNext)
length++;
return length;
};
void AddNote(SynthNote *inNote)
{
#if DEBUG_PRINT
printf("AddNote(inNote=%p) to state: %lu\n", inNote, mState);
#endif
#if USE_SANITY_CHECK
SanityCheck();
#endif
inNote->SetState(mState);
inNote->mNext = mHead;
inNote->mPrev = NULL;
if (mHead) { mHead->mPrev = inNote; mHead = inNote; }
else mHead = mTail = inNote;
#if USE_SANITY_CHECK
SanityCheck();
#endif
}
void RemoveNote(SynthNote *inNote)
{
#if DEBUG_PRINT
printf("RemoveNote(inNote=%p) from state: %lu\n", inNote, mState);
#endif
#if USE_SANITY_CHECK
SanityCheck();
#endif
if (inNote->mPrev) inNote->mPrev->mNext = inNote->mNext;
else mHead = inNote->mNext;
if (inNote->mNext) inNote->mNext->mPrev = inNote->mPrev;
else mTail = inNote->mPrev;
inNote->mPrev = 0;
inNote->mNext = 0;
#if USE_SANITY_CHECK
SanityCheck();
#endif
}
void TransferAllFrom(SynthNoteList *inNoteList, UInt32 inFrame)
{
#if DEBUG_PRINT
printf("TransferAllFrom: from state %lu into state %lu\n", inNoteList->mState, mState);
#endif
#if USE_SANITY_CHECK
SanityCheck();
inNoteList->SanityCheck();
#endif
if (!inNoteList->mTail) return;
if (mState == kNoteState_Released)
{
for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
{
#if DEBUG_PRINT
printf("TransferAllFrom: releasing note %p\n", note);
#endif
note->Release(inFrame);
note->SetState(mState);
}
}
else
{
for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
{
note->SetState(mState);
}
}
inNoteList->mTail->mNext = mHead;
if (mHead) mHead->mPrev = inNoteList->mTail;
else mTail = inNoteList->mTail;
mHead = inNoteList->mHead;
inNoteList->mHead = NULL;
inNoteList->mTail = NULL;
#if USE_SANITY_CHECK
SanityCheck();
inNoteList->SanityCheck();
#endif
}
SynthNote* FindOldestNote()
{
#if DEBUG_PRINT
printf("FindOldestNote\n");
#endif
#if USE_SANITY_CHECK
SanityCheck();
#endif
UInt64 minStartFrame = -1;
SynthNote* oldestNote = NULL;
for (SynthNote* note = mHead; note; note = note->mNext)
{
if (note->mAbsoluteStartFrame < minStartFrame)
{
oldestNote = note;
minStartFrame = note->mAbsoluteStartFrame;
}
}
return oldestNote;
}
SynthNote* FindMostQuietNote()
{
#if DEBUG_PRINT
printf("FindMostQuietNote\n");
#endif
Float32 minAmplitude = 1e9f;
UInt64 minStartFrame = -1;
SynthNote* mostQuietNote = NULL;
for (SynthNote* note = mHead; note; note = note->mNext)
{
Float32 amp = note->Amplitude();
#if DEBUG_PRINT
printf(" amp %g minAmplitude %g\n", amp, minAmplitude);
#endif
if (amp < minAmplitude)
{
mostQuietNote = note;
minAmplitude = amp;
minStartFrame = note->mAbsoluteStartFrame;
}
else if (amp == minAmplitude && note->mAbsoluteStartFrame < minStartFrame)
{
// use earliest start time as a tie breaker
mostQuietNote = note;
minStartFrame = note->mAbsoluteStartFrame;
}
}
#if USE_SANITY_CHECK
SanityCheck();
#endif
return mostQuietNote;
}
void SanityCheck() const;
SynthNoteState mState;
SynthNote * mHead;
SynthNote * mTail;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif

View File

@@ -0,0 +1,88 @@
/*
File: AUViewLocalizedStringKeys.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUViewLocalizedStringKeys_h__
#define __AUViewLocalizedStringKeys_h__
// ACCESS POINT:
#define kLocalizedStringBundle_AUView CFSTR("com.apple.audio.units.Components")
#define kLocalizedStringTable_AUView CFSTR("CustomUI")
// UNLOCALIZED STRINGS:
#define kAUViewUnlocalizedString_TitleSeparator CFSTR(": ")
// Generic View:
#define kAUViewLocalizedStringKey_AudioUnit CFSTR("Audio Unit")
#define kAUViewLocalizedStringKey_Manufacturer CFSTR("Manufacturer")
#define kAUViewLocalizedStringKey_FactoryPreset CFSTR("Factory Preset")
#define kAUViewLocalizedStringKey_Properties CFSTR("Properties")
#define kAUViewLocalizedStringKey_Parameters CFSTR("Parameters")
#define kAUViewLocalizedStringKey_Standard CFSTR("Standard")
#define kAUViewLocalizedStringKey_Expert CFSTR("Expert")
// AULoadCPU:
#define kAUViewLocalizedStringKey_RestrictCPULoad CFSTR("Restrict CPU Load")
#define kAUViewLocalizedStringKey_PercentSymbol CFSTR("%")
#define kAUViewLocalizedStringKey_NotApplicable CFSTR("n/a")
// AUDiskStreamingCheckbox:
#define kAUViewLocalizedStringKey_StreamFromDisk CFSTR("Stream From Disk")
// AURenderQualityPopup:
#define kAUViewLocalizedStringKey_RenderQuality CFSTR("Render Quality")
#define kAUViewLocalizedStringKey_Maximum CFSTR("Maximum")
#define kAUViewLocalizedStringKey_High CFSTR("High")
#define kAUViewLocalizedStringKey_Medium CFSTR("Medium")
#define kAUViewLocalizedStringKey_Low CFSTR("Low")
#define kAUViewLocalizedStringKey_Minimum CFSTR("Minimum")
// AUChannelLayoutPopUp:
#define kAUViewLocalizedStringKey_AudioChannelLayout CFSTR("Audio Channel Layout")
#endif //__AUViewLocalizedStringKeys_h__

View File

@@ -0,0 +1,466 @@
/*
File: AUEffectBase.cpp
Abstract: AUEffectBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUEffectBase.h"
/*
This class does not deal as well as it should with N-M effects...
The problem areas are (if the channels don't match):
ProcessInPlace if the channels don't match - there will be problems if InputChan != OutputChan
Bypass - its just passing the buffers through when not processing them
This will be fixed in a future update...
*/
//_____________________________________________________________________________
//
AUEffectBase::AUEffectBase( AudioComponentInstance audioUnit,
bool inProcessesInPlace ) :
AUBase(audioUnit, 1, 1), // 1 in bus, 1 out bus
mBypassEffect(false),
mParamSRDep (false),
mProcessesInPlace(inProcessesInPlace),
mMainOutput(NULL), mMainInput(NULL)
#if TARGET_OS_IPHONE
, mOnlyOneKernel(false)
#endif
{
}
//_____________________________________________________________________________
//
AUEffectBase::~AUEffectBase()
{
Cleanup();
}
//_____________________________________________________________________________
//
void AUEffectBase::Cleanup()
{
for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); ++it)
delete *it;
mKernelList.clear();
mMainOutput = NULL;
mMainInput = NULL;
}
//_____________________________________________________________________________
//
OSStatus AUEffectBase::Initialize()
{
// get our current numChannels for input and output
SInt16 auNumInputs = (SInt16) GetInput(0)->GetStreamFormat().mChannelsPerFrame;
SInt16 auNumOutputs = (SInt16) GetOutput(0)->GetStreamFormat().mChannelsPerFrame;
// does the unit publish specific information about channel configurations?
const AUChannelInfo *auChannelConfigs = NULL;
UInt32 numIOconfigs = SupportedNumChannels(&auChannelConfigs);
if ((numIOconfigs > 0) && (auChannelConfigs != NULL))
{
bool foundMatch = false;
for (UInt32 i = 0; (i < numIOconfigs) && !foundMatch; ++i)
{
SInt16 configNumInputs = auChannelConfigs[i].inChannels;
SInt16 configNumOutputs = auChannelConfigs[i].outChannels;
if ((configNumInputs < 0) && (configNumOutputs < 0))
{
// unit accepts any number of channels on input and output
if (((configNumInputs == -1) && (configNumOutputs == -2))
|| ((configNumInputs == -2) && (configNumOutputs == -1)))
{
foundMatch = true;
// unit accepts any number of channels on input and output IFF they are the same number on both scopes
}
else if (((configNumInputs == -1) && (configNumOutputs == -1)) && (auNumInputs == auNumOutputs))
{
foundMatch = true;
// unit has specified a particular number of channels on both scopes
}
else
continue;
}
else
{
// the -1 case on either scope is saying that the unit doesn't care about the
// number of channels on that scope
bool inputMatch = (auNumInputs == configNumInputs) || (configNumInputs == -1);
bool outputMatch = (auNumOutputs == configNumOutputs) || (configNumOutputs == -1);
if (inputMatch && outputMatch)
foundMatch = true;
}
}
if (!foundMatch)
return kAudioUnitErr_FormatNotSupported;
}
else
{
// there is no specifically published channel info
// so for those kinds of effects, the assumption is that the channels (whatever their number)
// should match on both scopes
if ((auNumOutputs != auNumInputs) || (auNumOutputs == 0))
{
return kAudioUnitErr_FormatNotSupported;
}
}
MaintainKernels();
mMainOutput = GetOutput(0);
mMainInput = GetInput(0);
const CAStreamBasicDescription& format = GetStreamFormat(kAudioUnitScope_Output, 0);
format.IdentifyCommonPCMFormat(mCommonPCMFormat, NULL);
mBytesPerFrame = format.mBytesPerFrame;
return noErr;
}
OSStatus AUEffectBase::Reset( AudioUnitScope inScope,
AudioUnitElement inElement)
{
for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); ++it) {
AUKernelBase *kernel = *it;
if (kernel != NULL)
kernel->Reset();
}
return AUBase::Reset(inScope, inElement);
}
OSStatus AUEffectBase::GetPropertyInfo (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
if (inScope == kAudioUnitScope_Global) {
switch (inID) {
case kAudioUnitProperty_BypassEffect:
outWritable = true;
outDataSize = sizeof (UInt32);
return noErr;
case kAudioUnitProperty_InPlaceProcessing:
outWritable = true;
outDataSize = sizeof (UInt32);
return noErr;
}
}
return AUBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
OSStatus AUEffectBase::GetProperty (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
if (inScope == kAudioUnitScope_Global) {
switch (inID) {
case kAudioUnitProperty_BypassEffect:
*((UInt32*)outData) = (IsBypassEffect() ? 1 : 0);
return noErr;
case kAudioUnitProperty_InPlaceProcessing:
*((UInt32*)outData) = (mProcessesInPlace ? 1 : 0);
return noErr;
}
}
return AUBase::GetProperty (inID, inScope, inElement, outData);
}
OSStatus AUEffectBase::SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
if (inScope == kAudioUnitScope_Global) {
switch (inID) {
case kAudioUnitProperty_BypassEffect:
{
if (inDataSize < sizeof(UInt32))
return kAudioUnitErr_InvalidPropertyValue;
bool tempNewSetting = *((UInt32*)inData) != 0;
// we're changing the state of bypass
if (tempNewSetting != IsBypassEffect())
{
if (!tempNewSetting && IsBypassEffect() && IsInitialized()) // turning bypass off and we're initialized
Reset(0, 0);
SetBypassEffect (tempNewSetting);
}
return noErr;
}
case kAudioUnitProperty_InPlaceProcessing:
mProcessesInPlace = (*((UInt32*)inData) != 0);
return noErr;
}
}
return AUBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
}
void AUEffectBase::MaintainKernels()
{
#if TARGET_OS_IPHONE
UInt32 nKernels = mOnlyOneKernel ? 1 : GetNumberOfChannels();
#else
UInt32 nKernels = GetNumberOfChannels();
#endif
if (mKernelList.size() < nKernels) {
mKernelList.reserve(nKernels);
for (UInt32 i = (UInt32)mKernelList.size(); i < nKernels; ++i)
mKernelList.push_back(NewKernel());
} else {
while (mKernelList.size() > nKernels) {
AUKernelBase *kernel = mKernelList.back();
delete kernel;
mKernelList.pop_back();
}
}
for(unsigned int i = 0; i < nKernels; i++ )
{
if(mKernelList[i]) {
mKernelList[i]->SetChannelNum (i);
}
}
}
bool AUEffectBase::StreamFormatWritable( AudioUnitScope scope,
AudioUnitElement element)
{
return IsInitialized() ? false : true;
}
OSStatus AUEffectBase::ChangeStreamFormat( AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inPrevFormat,
const CAStreamBasicDescription & inNewFormat)
{
OSStatus result = AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat);
if (result == noErr)
{
// for the moment this only dependency we know about
// where a parameter's range may change is with the sample rate
// and effects are only publishing parameters in the global scope!
if (GetParamHasSampleRateDependency() && fnotequal(inPrevFormat.mSampleRate, inNewFormat.mSampleRate))
PropertyChanged(kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0);
}
return result;
}
// ____________________________________________________________________________
//
// This method is called (potentially repeatedly) by ProcessForScheduledParams()
// in order to perform the actual DSP required for this portion of the entire buffer
// being processed. The entire buffer can be divided up into smaller "slices"
// according to the timestamps on the scheduled parameters...
//
OSStatus AUEffectBase::ProcessScheduledSlice( void *inUserData,
UInt32 inStartFrameInBuffer,
UInt32 inSliceFramesToProcess,
UInt32 inTotalBufferFrames )
{
ScheduledProcessParams &sliceParams = *((ScheduledProcessParams*)inUserData);
AudioUnitRenderActionFlags &actionFlags = *sliceParams.actionFlags;
AudioBufferList &inputBufferList = *sliceParams.inputBufferList;
AudioBufferList &outputBufferList = *sliceParams.outputBufferList;
UInt32 channelSize = inSliceFramesToProcess * mBytesPerFrame;
// fix the size of the buffer we're operating on before we render this slice of time
for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) {
inputBufferList.mBuffers[i].mDataByteSize = inputBufferList.mBuffers[i].mNumberChannels * channelSize;
}
for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) {
outputBufferList.mBuffers[i].mDataByteSize = outputBufferList.mBuffers[i].mNumberChannels * channelSize;
}
// process the buffer
OSStatus result = ProcessBufferLists(actionFlags, inputBufferList, outputBufferList, inSliceFramesToProcess );
// we just partially processed the buffers, so increment the data pointers to the next part of the buffer to process
for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) {
inputBufferList.mBuffers[i].mData =
(char *)inputBufferList.mBuffers[i].mData + inputBufferList.mBuffers[i].mNumberChannels * channelSize;
}
for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) {
outputBufferList.mBuffers[i].mData =
(char *)outputBufferList.mBuffers[i].mData + outputBufferList.mBuffers[i].mNumberChannels * channelSize;
}
return result;
}
// ____________________________________________________________________________
//
OSStatus AUEffectBase::Render( AudioUnitRenderActionFlags &ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 nFrames)
{
if (!HasInput(0))
return kAudioUnitErr_NoConnection;
OSStatus result = noErr;
result = mMainInput->PullInput(ioActionFlags, inTimeStamp, 0 /* element */, nFrames);
if (result == noErr)
{
if(ProcessesInPlace() && mMainOutput->WillAllocateBuffer())
{
mMainOutput->SetBufferList(mMainInput->GetBufferList() );
}
if (ShouldBypassEffect())
{
// leave silence bit alone
if(!ProcessesInPlace() )
{
mMainInput->CopyBufferContentsTo (mMainOutput->GetBufferList());
}
}
else
{
if(mParamList.size() == 0 )
{
// this will read/write silence bit
result = ProcessBufferLists(ioActionFlags, mMainInput->GetBufferList(), mMainOutput->GetBufferList(), nFrames);
}
else
{
// deal with scheduled parameters...
AudioBufferList &inputBufferList = mMainInput->GetBufferList();
AudioBufferList &outputBufferList = mMainOutput->GetBufferList();
ScheduledProcessParams processParams;
processParams.actionFlags = &ioActionFlags;
processParams.inputBufferList = &inputBufferList;
processParams.outputBufferList = &outputBufferList;
// divide up the buffer into slices according to scheduled params then
// do the DSP for each slice (ProcessScheduledSlice() called for each slice)
result = ProcessForScheduledParams( mParamList,
nFrames,
&processParams );
// fixup the buffer pointers to how they were before we started
UInt32 channelSize = nFrames * mBytesPerFrame;
for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) {
UInt32 size = inputBufferList.mBuffers[i].mNumberChannels * channelSize;
inputBufferList.mBuffers[i].mData = (char *)inputBufferList.mBuffers[i].mData - size;
inputBufferList.mBuffers[i].mDataByteSize = size;
}
for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) {
UInt32 size = outputBufferList.mBuffers[i].mNumberChannels * channelSize;
outputBufferList.mBuffers[i].mData = (char *)outputBufferList.mBuffers[i].mData - size;
outputBufferList.mBuffers[i].mDataByteSize = size;
}
}
}
if ( (ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) && !ProcessesInPlace() )
{
AUBufferList::ZeroBuffer(mMainOutput->GetBufferList() );
}
}
return result;
}
OSStatus AUEffectBase::ProcessBufferLists(
AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer,
AudioBufferList & outBuffer,
UInt32 inFramesToProcess )
{
if (ShouldBypassEffect())
return noErr;
// interleaved (or mono)
switch (mCommonPCMFormat) {
case CAStreamBasicDescription::kPCMFormatFloat32 :
ProcessBufferListsT<Float32>(ioActionFlags, inBuffer, outBuffer, inFramesToProcess);
break;
case CAStreamBasicDescription::kPCMFormatFixed824 :
ProcessBufferListsT<SInt32>(ioActionFlags, inBuffer, outBuffer, inFramesToProcess);
break;
case CAStreamBasicDescription::kPCMFormatInt16 :
ProcessBufferListsT<SInt16>(ioActionFlags, inBuffer, outBuffer, inFramesToProcess);
break;
default :
throw CAException(kAudio_UnimplementedError);
}
return noErr;
}
Float64 AUEffectBase::GetSampleRate()
{
return GetOutput(0)->GetStreamFormat().mSampleRate;
}
UInt32 AUEffectBase::GetNumberOfChannels()
{
return GetOutput(0)->GetStreamFormat().mChannelsPerFrame;
}

View File

@@ -0,0 +1,377 @@
/*
File: AUEffectBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUEffectBase_h__
#define __AUEffectBase_h__
#include "AUBase.h"
#include "AUSilentTimeout.h"
#include "CAException.h"
class AUKernelBase;
// Base class for an effect with one input stream, one output stream,
// any number of channels.
/*! @class AUEffectBase */
class AUEffectBase : public AUBase {
public:
/*! @ctor AUEffectBase */
AUEffectBase( AudioComponentInstance audioUnit,
bool inProcessesInPlace = true );
/*! @dtor ~AUEffectBase */
~AUEffectBase();
/*! @method Initialize */
virtual OSStatus Initialize();
/*! @method Cleanup */
virtual void Cleanup();
/*! @method Reset */
virtual OSStatus Reset( AudioUnitScope inScope,
AudioUnitElement inElement);
/*! @method GetPropertyInfo */
virtual OSStatus GetPropertyInfo (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable);
/*! @method GetProperty */
virtual OSStatus GetProperty (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
/*! @method SetProperty */
virtual OSStatus SetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize);
/*! @method StreamFormatWritable */
virtual bool StreamFormatWritable (AudioUnitScope scope,
AudioUnitElement element);
/*! @method ChangeStreamFormat */
virtual OSStatus ChangeStreamFormat (
AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inPrevFormat,
const CAStreamBasicDescription & inNewFormat);
/*! @method Render */
virtual OSStatus Render(AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames);
// our virtual methods
// If your unit processes N to N channels, and there are no interactions between channels,
// it can override NewKernel to create a mono processing object per channel. Otherwise,
// don't override NewKernel, and instead, override ProcessBufferLists.
/*! @method NewKernel */
virtual AUKernelBase * NewKernel() { return NULL; }
/*! @method ProcessBufferLists */
virtual OSStatus ProcessBufferLists(
AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer,
AudioBufferList & outBuffer,
UInt32 inFramesToProcess );
// convenience format accessors (use output 0's format)
/*! @method GetSampleRate */
Float64 GetSampleRate();
/*! @method GetNumberOfChannels */
UInt32 GetNumberOfChannels();
// convenience wrappers for accessing parameters in the global scope
/*! @method SetParameter */
using AUBase::SetParameter;
void SetParameter( AudioUnitParameterID paramID,
AudioUnitParameterValue value)
{
Globals()->SetParameter(paramID, value);
}
/*! @method GetParameter */
using AUBase::GetParameter;
AudioUnitParameterValue GetParameter( AudioUnitParameterID paramID )
{
return Globals()->GetParameter(paramID );
}
/*! @method CanScheduleParameters */
virtual bool CanScheduleParameters() const { return true; }
/*! @method IsBypassEffect */
// This is used for the property value - to reflect to the UI if an effect is bypassed
bool IsBypassEffect () { return mBypassEffect; }
protected:
/*! @method MaintainKernels */
void MaintainKernels();
/*! @method ShouldBypassEffect */
// This is used in the render call to see if an effect is bypassed
// It can return a different status than IsBypassEffect (though it MUST take that into account)
virtual bool ShouldBypassEffect () { return IsBypassEffect(); }
public:
/*! @method SetBypassEffect */
virtual void SetBypassEffect (bool inFlag) { mBypassEffect = inFlag; }
/*! @method SetParamHasSampleRateDependency */
void SetParamHasSampleRateDependency (bool inFlag)
{
mParamSRDep = inFlag;
}
/*! @method GetParamHasSampleRateDependency */
bool GetParamHasSampleRateDependency () const { return mParamSRDep; }
struct ScheduledProcessParams // pointer passed in as void* userData param for ProcessScheduledSlice()
{
AudioUnitRenderActionFlags *actionFlags;
AudioBufferList *inputBufferList;
AudioBufferList *outputBufferList;
};
virtual OSStatus ProcessScheduledSlice( void *inUserData,
UInt32 inStartFrameInBuffer,
UInt32 inSliceFramesToProcess,
UInt32 inTotalBufferFrames );
bool ProcessesInPlace() const {return mProcessesInPlace;};
void SetProcessesInPlace(bool inProcessesInPlace) {mProcessesInPlace = inProcessesInPlace;};
typedef std::vector<AUKernelBase *> KernelList;
protected:
/*! @var mKernelList */
KernelList mKernelList;
AUKernelBase* GetKernel(UInt32 index) { return mKernelList[index]; }
/*! @method IsInputSilent */
bool IsInputSilent (AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess)
{
bool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0;
// take latency and tail time into account when propagating the silent bit
UInt32 silentTimeoutFrames = UInt32(GetSampleRate() * (GetLatency() + GetTailTime()));
mSilentTimeout.Process (inFramesToProcess, silentTimeoutFrames, inputSilent);
return inputSilent;
}
#if TARGET_OS_IPHONE
void SetOnlyOneKernel(bool inUseOnlyOneKernel) { mOnlyOneKernel = inUseOnlyOneKernel; } // set in ctor of subclass that wants it.
#endif
template <typename T>
void ProcessBufferListsT(
AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer,
AudioBufferList & outBuffer,
UInt32 inFramesToProcess );
CAStreamBasicDescription::CommonPCMFormat GetCommonPCMFormat() const { return mCommonPCMFormat; }
private:
/*! @var mBypassEffect */
bool mBypassEffect;
/*! @var mParamSRDep */
bool mParamSRDep;
/*! @var mProcessesInplace */
bool mProcessesInPlace;
/*! @var mSilentTimeout */
AUSilentTimeout mSilentTimeout;
/*! @var mMainOutput */
AUOutputElement * mMainOutput;
/*! @var mMainInput */
AUInputElement * mMainInput;
#if TARGET_OS_IPHONE
/*! @var mOnlyOneKernel */
bool mOnlyOneKernel;
#endif
/*! @var mCommonPCMFormat */
CAStreamBasicDescription::CommonPCMFormat mCommonPCMFormat;
UInt32 mBytesPerFrame;
};
// Base class for a "kernel", an object that performs DSP on one channel of an interleaved stream.
/*! @class AUKernelBase */
class AUKernelBase {
public:
/*! @ctor AUKernelBase */
AUKernelBase(AUEffectBase *inAudioUnit ) :
mAudioUnit(inAudioUnit) { }
/*! @dtor ~AUKernelBase */
virtual ~AUKernelBase() { }
/*! @method Reset */
virtual void Reset() { }
/*! @method Process */
virtual void Process( const Float32 * inSourceP,
Float32 * inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); }
/*! @method Process */
virtual void Process( const SInt32 * inSourceP,
SInt32 * inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); }
/*! @method Process */
virtual void Process( const SInt16 * inSourceP,
SInt16 * inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); }
/*! @method GetSampleRate */
Float64 GetSampleRate()
{
return mAudioUnit->GetSampleRate();
}
/*! @method GetParameter */
AudioUnitParameterValue GetParameter (AudioUnitParameterID paramID)
{
return mAudioUnit->GetParameter(paramID);
}
void SetChannelNum (UInt32 inChan) { mChannelNum = inChan; }
UInt32 GetChannelNum () { return mChannelNum; }
protected:
/*! @var mAudioUnit */
AUEffectBase * mAudioUnit;
UInt32 mChannelNum;
};
template <typename T>
void AUEffectBase::ProcessBufferListsT(
AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer,
AudioBufferList & outBuffer,
UInt32 inFramesToProcess )
{
bool ioSilence;
bool silentInput = IsInputSilent (ioActionFlags, inFramesToProcess);
ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
// call the kernels to handle either interleaved or deinterleaved
if (inBuffer.mNumberBuffers == 1) {
if (inBuffer.mBuffers[0].mNumberChannels == 0)
throw CAException(kAudio_ParamError);
for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) {
AUKernelBase *kernel = mKernelList[channel];
if (kernel == NULL) continue;
ioSilence = silentInput;
// process each interleaved channel individually
kernel->Process(
(const T *)inBuffer.mBuffers[0].mData + channel,
(T *)outBuffer.mBuffers[0].mData + channel,
inFramesToProcess,
inBuffer.mBuffers[0].mNumberChannels,
ioSilence);
if (!ioSilence)
ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
}
} else {
for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) {
AUKernelBase *kernel = mKernelList[channel];
if (kernel == NULL) continue;
ioSilence = silentInput;
const AudioBuffer *srcBuffer = &inBuffer.mBuffers[channel];
AudioBuffer *destBuffer = &outBuffer.mBuffers[channel];
kernel->Process(
(const T *)srcBuffer->mData,
(T *)destBuffer->mData,
inFramesToProcess,
1,
ioSilence);
if (!ioSilence)
ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
}
}
}
#endif // __AUEffectBase_h__

View File

@@ -0,0 +1,495 @@
/*
File: AUMIDIBase.cpp
Abstract: AUMIDIBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUMIDIBase.h"
#include <CoreMIDI/CoreMIDI.h>
#include "CAXException.h"
//temporaray location
enum
{
kMidiMessage_NoteOff = 0x80,
kMidiMessage_NoteOn = 0x90,
kMidiMessage_PolyPressure = 0xA0,
kMidiMessage_ControlChange = 0xB0,
kMidiMessage_ProgramChange = 0xC0,
kMidiMessage_ChannelPressure = 0xD0,
kMidiMessage_PitchWheel = 0xE0,
kMidiController_AllSoundOff = 120,
kMidiController_ResetAllControllers = 121,
kMidiController_AllNotesOff = 123
};
AUMIDIBase::AUMIDIBase(AUBase* inBase)
: mAUBaseInstance (*inBase)
{
#if CA_AUTO_MIDI_MAP
mMapManager = new CAAUMIDIMapManager();
#endif
}
AUMIDIBase::~AUMIDIBase()
{
#if CA_AUTO_MIDI_MAP
if (mMapManager)
delete mMapManager;
#endif
}
#if TARGET_API_MAC_OSX
OSStatus AUMIDIBase::DelegateGetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
OSStatus result = noErr;
switch (inID) {
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_MIDIXMLNames:
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
if (GetXMLNames(NULL) == noErr) {
outDataSize = sizeof(CFURLRef);
outWritable = false;
} else
result = kAudioUnitErr_InvalidProperty;
break;
#endif
#if CA_AUTO_MIDI_MAP
case kAudioUnitProperty_AllParameterMIDIMappings:
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
outWritable = true;
outDataSize = sizeof (AUParameterMIDIMapping)*mMapManager->NumMaps();
result = noErr;
break;
case kAudioUnitProperty_HotMapParameterMIDIMapping:
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
outWritable = true;
outDataSize = sizeof (AUParameterMIDIMapping);
result = noErr;
break;
case kAudioUnitProperty_AddParameterMIDIMapping:
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
outWritable = true;
outDataSize = sizeof (AUParameterMIDIMapping);
result = noErr;
break;
case kAudioUnitProperty_RemoveParameterMIDIMapping:
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
outWritable = true;
outDataSize = sizeof (AUParameterMIDIMapping);
result = noErr;
break;
#endif
default:
result = kAudioUnitErr_InvalidProperty;
break;
}
return result;
#if CA_AUTO_MIDI_MAP || (!TARGET_OS_IPHONE)
InvalidScope:
return kAudioUnitErr_InvalidScope;
InvalidElement:
return kAudioUnitErr_InvalidElement;
#endif
}
OSStatus AUMIDIBase::DelegateGetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
OSStatus result;
switch (inID) {
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_MIDIXMLNames:
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
result = GetXMLNames((CFURLRef *)outData);
break;
#endif
#if CA_AUTO_MIDI_MAP
case kAudioUnitProperty_AllParameterMIDIMappings:{
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
AUParameterMIDIMapping* maps = (static_cast<AUParameterMIDIMapping*>(outData));
mMapManager->GetMaps(maps);
// printf ("GETTING MAPS\n");
// mMapManager->Print();
result = noErr;
break;
}
case kAudioUnitProperty_HotMapParameterMIDIMapping:{
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
AUParameterMIDIMapping * map = (static_cast<AUParameterMIDIMapping*>(outData));
mMapManager->GetHotParameterMap (*map);
result = noErr;
break;
}
#endif
default:
result = kAudioUnitErr_InvalidProperty;
break;
}
return result;
#if CA_AUTO_MIDI_MAP || (!TARGET_OS_IPHONE)
InvalidScope:
return kAudioUnitErr_InvalidScope;
InvalidElement:
return kAudioUnitErr_InvalidElement;
#endif
}
OSStatus AUMIDIBase::DelegateSetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
OSStatus result;
switch (inID) {
#if CA_AUTO_MIDI_MAP
case kAudioUnitProperty_AddParameterMIDIMapping:{
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData;
mMapManager->SortedInsertToParamaterMaps (maps, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance);
mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);
result = noErr;
break;
}
case kAudioUnitProperty_RemoveParameterMIDIMapping:{
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData;
bool didChange;
mMapManager->SortedRemoveFromParameterMaps(maps, (inDataSize / sizeof(AUParameterMIDIMapping)), didChange);
if (didChange)
mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);
result = noErr;
break;
}
case kAudioUnitProperty_HotMapParameterMIDIMapping:{
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
AUParameterMIDIMapping & map = *((AUParameterMIDIMapping*)inData);
mMapManager->SetHotMapping (map);
result = noErr;
break;
}
case kAudioUnitProperty_AllParameterMIDIMappings:{
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
ca_require(inElement == 0, InvalidElement);
AUParameterMIDIMapping * mappings = (AUParameterMIDIMapping*)inData;
mMapManager->ReplaceAllMaps (mappings, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance);
result = noErr;
break;
}
#endif
default:
result = kAudioUnitErr_InvalidProperty;
break;
}
return result;
#if CA_AUTO_MIDI_MAP
InvalidScope:
return kAudioUnitErr_InvalidScope;
InvalidElement:
return kAudioUnitErr_InvalidElement;
#endif
}
#endif //TARGET_API_MAC_OSX
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ____MidiDispatch
inline const Byte * NextMIDIEvent(const Byte *event, const Byte *end)
{
Byte c = *event;
switch (c >> 4) {
default: // data byte -- assume in sysex
while ((*++event & 0x80) == 0 && event < end)
;
break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
case 0xE:
event += 3;
break;
case 0xC:
case 0xD:
event += 2;
break;
case 0xF:
switch (c) {
case 0xF0:
while ((*++event & 0x80) == 0 && event < end)
;
break;
case 0xF1:
case 0xF3:
event += 2;
break;
case 0xF2:
event += 3;
break;
default:
++event;
break;
}
}
return (event >= end) ? end : event;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUMIDIBase::HandleMIDIPacketList
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus AUMIDIBase::HandleMIDIPacketList(const MIDIPacketList *pktlist)
{
if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
int nPackets = pktlist->numPackets;
const MIDIPacket *pkt = pktlist->packet;
while (nPackets-- > 0) {
const Byte *event = pkt->data, *packetEnd = event + pkt->length;
long startFrame = (long)pkt->timeStamp;
while (event < packetEnd) {
Byte status = event[0];
if (status & 0x80) {
// really a status byte (not sysex continuation)
HandleMidiEvent(status & 0xF0, status & 0x0F, event[1], event[2], static_cast<UInt32>(startFrame));
// note that we're generating a bogus channel number for system messages (0xF0-FF)
}
event = NextMIDIEvent(event, packetEnd);
}
pkt = reinterpret_cast<const MIDIPacket *>(packetEnd);
}
return noErr;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AUMIDIBase::HandleMidiEvent
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus AUMIDIBase::HandleMidiEvent(UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame)
{
if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
#if CA_AUTO_MIDI_MAP
// you potentially have a choice to make here - if a param mapping matches, do you still want to process the
// MIDI event or not. The default behaviour is to continue on with the MIDI event.
if (mMapManager->HandleHotMapping (status, channel, data1, mAUBaseInstance)) {
mAUBaseInstance.PropertyChanged (kAudioUnitProperty_HotMapParameterMIDIMapping, kAudioUnitScope_Global, 0);
}
else {
mMapManager->FindParameterMapEventMatch(status, channel, data1, data2, inStartFrame, mAUBaseInstance);
}
#endif
OSStatus result = noErr;
switch(status)
{
case kMidiMessage_NoteOn:
if(data2)
{
result = HandleNoteOn(channel, data1, data2, inStartFrame);
}
else
{
// zero velocity translates to note off
result = HandleNoteOff(channel, data1, data2, inStartFrame);
}
break;
case kMidiMessage_NoteOff:
result = HandleNoteOff(channel, data1, data2, inStartFrame);
break;
default:
result = HandleNonNoteEvent (status, channel, data1, data2, inStartFrame);
break;
}
return result;
}
OSStatus AUMIDIBase::HandleNonNoteEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame)
{
OSStatus result = noErr;
switch (status)
{
case kMidiMessage_PitchWheel:
result = HandlePitchWheel(channel, data1, data2, inStartFrame);
break;
case kMidiMessage_ProgramChange:
result = HandleProgramChange(channel, data1);
break;
case kMidiMessage_ChannelPressure:
result = HandleChannelPressure(channel, data1, inStartFrame);
break;
case kMidiMessage_ControlChange:
{
switch (data1) {
case kMidiController_AllNotesOff:
result = HandleAllNotesOff(channel);
break;
case kMidiController_ResetAllControllers:
result = HandleResetAllControllers(channel);
break;
case kMidiController_AllSoundOff:
result = HandleAllSoundOff(channel);
break;
default:
result = HandleControlChange(channel, data1, data2, inStartFrame);
break;
}
break;
}
case kMidiMessage_PolyPressure:
result = HandlePolyPressure (channel, data1, data2, inStartFrame);
break;
}
return result;
}
OSStatus AUMIDIBase::SysEx (const UInt8 * inData,
UInt32 inLength)
{
if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
return HandleSysEx(inData, inLength );
}
#if TARGET_OS_MAC
#if __LP64__
// comp instance, parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_index + 1];
#else
// parameters in reverse order, then comp instance
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_nparams - 1 - _index];
#endif
#elif TARGET_OS_WIN32
// (no comp instance), parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_index];
#endif
#if !CA_USE_AUDIO_PLUGIN_ONLY
OSStatus AUMIDIBase::ComponentEntryDispatch( ComponentParameters * params,
AUMIDIBase * This)
{
if (This == NULL) return kAudio_ParamError;
OSStatus result;
switch (params->what) {
case kMusicDeviceMIDIEventSelect:
{
PARAM(UInt32, pbinStatus, 0, 4);
PARAM(UInt32, pbinData1, 1, 4);
PARAM(UInt32, pbinData2, 2, 4);
PARAM(UInt32, pbinOffsetSampleFrame, 3, 4);
result = This->MIDIEvent(pbinStatus, pbinData1, pbinData2, pbinOffsetSampleFrame);
}
break;
case kMusicDeviceSysExSelect:
{
PARAM(const UInt8 *, pbinData, 0, 2);
PARAM(UInt32, pbinLength, 1, 2);
result = This->SysEx(pbinData, pbinLength);
}
break;
default:
result = badComponentSelector;
break;
}
return result;
}
#endif

View File

@@ -0,0 +1,213 @@
/*
File: AUMIDIBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUMIDIBase_h__
#define __AUMIDIBase_h__
#include "AUBase.h"
#if CA_AUTO_MIDI_MAP
#include "CAAUMIDIMapManager.h"
#endif
struct MIDIPacketList;
// ________________________________________________________________________
// MusicDeviceBase
//
/*! @class AUMIDIBase */
class AUMIDIBase {
public:
// this is NOT a copy constructor!
/*! @ctor AUMIDIBase */
AUMIDIBase(AUBase* inBase);
/*! @dtor ~AUMIDIBase */
virtual ~AUMIDIBase();
/*! @method MIDIEvent */
virtual OSStatus MIDIEvent( UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame)
{
UInt32 strippedStatus = inStatus & 0xf0;
UInt32 channel = inStatus & 0x0f;
return HandleMidiEvent(strippedStatus, channel, inData1, inData2, inOffsetSampleFrame);
}
/*! @method HandleMIDIPacketList */
OSStatus HandleMIDIPacketList(const MIDIPacketList *pktlist);
/*! @method SysEx */
virtual OSStatus SysEx( const UInt8 * inData,
UInt32 inLength);
#if TARGET_API_MAC_OSX
/*! @method DelegateGetPropertyInfo */
virtual OSStatus DelegateGetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable);
/*! @method DelegateGetProperty */
virtual OSStatus DelegateGetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
/*! @method DelegateSetProperty */
virtual OSStatus DelegateSetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize);
#endif
protected:
// MIDI dispatch
/*! @method HandleMidiEvent */
virtual OSStatus HandleMidiEvent( UInt8 inStatus,
UInt8 inChannel,
UInt8 inData1,
UInt8 inData2,
UInt32 inStartFrame);
/*! @method HandleNonNoteEvent */
virtual OSStatus HandleNonNoteEvent ( UInt8 status,
UInt8 channel,
UInt8 data1,
UInt8 data2,
UInt32 inStartFrame);
#if TARGET_API_MAC_OSX
/*! @method GetXMLNames */
virtual OSStatus GetXMLNames(CFURLRef *outNameDocument)
{ return kAudioUnitErr_InvalidProperty; } // if not overridden, it's unsupported
#endif
// channel messages
/*! @method HandleNoteOn */
virtual OSStatus HandleNoteOn( UInt8 inChannel,
UInt8 inNoteNumber,
UInt8 inVelocity,
UInt32 inStartFrame) { return noErr; }
/*! @method HandleNoteOff */
virtual OSStatus HandleNoteOff( UInt8 inChannel,
UInt8 inNoteNumber,
UInt8 inVelocity,
UInt32 inStartFrame) { return noErr; }
/*! @method HandleControlChange */
virtual OSStatus HandleControlChange( UInt8 inChannel,
UInt8 inController,
UInt8 inValue,
UInt32 inStartFrame) { return noErr; }
/*! @method HandlePitchWheel */
virtual OSStatus HandlePitchWheel( UInt8 inChannel,
UInt8 inPitch1,
UInt8 inPitch2,
UInt32 inStartFrame) { return noErr; }
/*! @method HandleChannelPressure */
virtual OSStatus HandleChannelPressure( UInt8 inChannel,
UInt8 inValue,
UInt32 inStartFrame) { return noErr; }
/*! @method HandleProgramChange */
virtual OSStatus HandleProgramChange( UInt8 inChannel,
UInt8 inValue) { return noErr; }
/*! @method HandlePolyPressure */
virtual OSStatus HandlePolyPressure( UInt8 inChannel,
UInt8 inKey,
UInt8 inValue,
UInt32 inStartFrame) { return noErr; }
/*! @method HandleResetAllControllers */
virtual OSStatus HandleResetAllControllers(UInt8 inChannel) { return noErr; }
/*! @method HandleAllNotesOff */
virtual OSStatus HandleAllNotesOff( UInt8 inChannel) { return noErr; }
/*! @method HandleAllSoundOff */
virtual OSStatus HandleAllSoundOff( UInt8 inChannel) { return noErr; }
//System messages
/*! @method HandleSysEx */
virtual OSStatus HandleSysEx( const UInt8 * inData,
UInt32 inLength ) { return noErr; }
#if CA_AUTO_MIDI_MAP
/* map manager */
CAAUMIDIMapManager *GetMIDIMapManager() {return mMapManager;};
#endif
private:
/*! @var mAUBaseInstance */
AUBase & mAUBaseInstance;
#if CA_AUTO_MIDI_MAP
/* map manager */
CAAUMIDIMapManager * mMapManager;
#endif
public:
#if !CA_USE_AUDIO_PLUGIN_ONLY
// component dispatcher
/*! @method ComponentEntryDispatch */
static OSStatus ComponentEntryDispatch( ComponentParameters *params,
AUMIDIBase *This);
#endif
};
#endif // __AUMIDIBase_h__

View File

@@ -0,0 +1,164 @@
/*
File: AUMIDIEffectBase.cpp
Abstract: AUMIDIEffectBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUMIDIEffectBase.h"
// compatibility with older OS SDK releases
typedef OSStatus
(*TEMP_MusicDeviceMIDIEventProc)( void * inComponentStorage,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame);
static OSStatus AUMIDIEffectBaseMIDIEvent(void * inComponentStorage,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame);
AUMIDIEffectBase::AUMIDIEffectBase( AudioComponentInstance inInstance,
bool inProcessesInPlace )
: AUEffectBase(inInstance, inProcessesInPlace),
AUMIDIBase(this)
{
}
OSStatus AUMIDIEffectBase::GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
OSStatus result;
result = AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
if (result == kAudioUnitErr_InvalidProperty)
result = AUMIDIBase::DelegateGetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
return result;
}
OSStatus AUMIDIEffectBase::GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
OSStatus result;
#if !CA_USE_AUDIO_PLUGIN_ONLY
if (inID == kAudioUnitProperty_FastDispatch) {
if (inElement == kMusicDeviceMIDIEventSelect) {
*(TEMP_MusicDeviceMIDIEventProc *)outData = AUMIDIEffectBaseMIDIEvent;
return noErr;
}
return kAudioUnitErr_InvalidElement;
}
#endif
result = AUEffectBase::GetProperty (inID, inScope, inElement, outData);
if (result == kAudioUnitErr_InvalidProperty)
result = AUMIDIBase::DelegateGetProperty (inID, inScope, inElement, outData);
return result;
}
OSStatus AUMIDIEffectBase::SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
OSStatus result = AUEffectBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
if (result == kAudioUnitErr_InvalidProperty)
result = AUMIDIBase::DelegateSetProperty (inID, inScope, inElement, inData, inDataSize);
return result;
}
#if !TARGET_OS_IPHONE
OSStatus AUMIDIEffectBase::ComponentEntryDispatch(ComponentParameters * params,
AUMIDIEffectBase * This)
{
if (This == NULL) return paramErr;
OSStatus result;
switch (params->what) {
case kMusicDeviceMIDIEventSelect:
case kMusicDeviceSysExSelect:
result = AUMIDIBase::ComponentEntryDispatch (params, This);
break;
default:
result = AUEffectBase::ComponentEntryDispatch(params, This);
break;
}
return result;
}
#endif
// fast dispatch
static OSStatus AUMIDIEffectBaseMIDIEvent(void * inComponentStorage,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame)
{
OSStatus result = noErr;
try {
AUMIDIEffectBase *This = static_cast<AUMIDIEffectBase *>(inComponentStorage);
if (This == NULL) return paramErr;
result = This->AUMIDIBase::MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
}
COMPONENT_CATCH
return result;
}

View File

@@ -0,0 +1,104 @@
/*
File: AUMIDIEffectBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUMIDIEffectBase_h__
#define __AUMIDIEffectBase_h__
#include "AUMIDIBase.h"
#include "AUEffectBase.h"
// ________________________________________________________________________
// AUMIDIEffectBase
//
/*! @class AUMIDIEffectBase */
class AUMIDIEffectBase : public AUEffectBase, public AUMIDIBase {
public:
/*! @ctor AUMIDIEffectBase */
AUMIDIEffectBase( AudioComponentInstance inInstance,
bool inProcessesInPlace = false );
/*! @method MIDIEvent */
virtual OSStatus MIDIEvent(UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame)
{
return AUMIDIBase::MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame);
}
/*! @method SysEx */
virtual OSStatus SysEx(const UInt8 * inData,
UInt32 inLength)
{
return AUMIDIBase::SysEx (inData, inLength);
}
/*! @method GetPropertyInfo */
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable);
/*! @method GetProperty */
virtual OSStatus GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
/*! @method SetProperty */
virtual OSStatus SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize);
#if !TARGET_OS_IPHONE
// component dispatcher
/*! @method ComponentEntryDispatch */
static OSStatus ComponentEntryDispatch( ComponentParameters * params,
AUMIDIEffectBase * This);
#endif
};
#endif // __AUMIDIEffectBase_h__

View File

@@ -0,0 +1,76 @@
/*
File: AUOutputBase.cpp
Abstract: AUOutputBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !CA_USE_AUDIO_PLUGIN_ONLY
#include "AUOutputBase.h"
OSStatus AUOutputBase::ComponentEntryDispatch(ComponentParameters *params, AUOutputBase *This)
{
if (This == NULL) return paramErr;
OSStatus result;
switch (params->what) {
case kAudioOutputUnitStartSelect:
{
result = This->Start();
}
break;
case kAudioOutputUnitStopSelect:
{
result = This->Stop();
}
break;
default:
result = badComponentSelector;
break;
}
return result;
}
#endif

View File

@@ -0,0 +1,82 @@
/*
File: AUOutputBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUOutputBase_h__
#define __AUOutputBase_h__
#include "AUBase.h"
// ________________________________________________________________________
// AUOutputBase
// this is now a mix-in rather than an AUBase subclass
/*! @class AUOutputBase */
class AUOutputBase {
public:
/*! @ctor AUOutputBase */
AUOutputBase(AUBase *inBase) : mAUBaseInstance(*inBase) { }
virtual ~AUOutputBase() { }
// additional component entry points
/*! @method Start */
virtual OSStatus Start() = 0;
/*! @method Stop */
virtual OSStatus Stop() = 0;
#if !CA_USE_AUDIO_PLUGIN_ONLY
// component dispatcher
/*! @method ComponentEntryDispatch */
static OSStatus ComponentEntryDispatch( ComponentParameters * params,
AUOutputBase * This);
#endif
private:
/*! @var mAUBaseInstance */
AUBase & mAUBaseInstance;
};
#endif // __AUOutputBase_h__

View File

@@ -0,0 +1,706 @@
/*
File: AUPannerBase.cpp
Abstract: AUPannerBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUPannerBase.h"
#include "CABundleLocker.h"
#include <AudioToolbox/AudioToolbox.h>
#include <Accelerate/Accelerate.h>
static bool sLocalized = false;
static CFStringRef kPanner_Azimuth_Name = CFSTR("azimuth");
static CFStringRef kPanner_Elevation_Name = CFSTR("elevation");
static CFStringRef kPanner_Distance_Name = CFSTR("distance");
static CFStringRef kPanner_CoordScale_Name = CFSTR("coordinate scale");
static CFStringRef kPanner_RefDistance_Name = CFSTR("reference distance");
static CFStringRef kPanner_Gain_Name = CFSTR("gain");
static Float32 kPannerParamDefault_Azimuth = 0.;
static Float32 kPannerParamDefault_Elevation = 0.;
static Float32 kPannerParamDefault_Distance = 1.;
static Float32 kPannerParamDefault_CoordScale = 10.;
static Float32 kPannerParamDefault_RefDistance = 1.;
static Float32 kPannerParamDefault_Gain = 1.;
//_____________________________________________________________________________
//
AUPannerBase::AUPannerBase(AudioComponentInstance inAudioUnit)
: AUBase(inAudioUnit, 1, 1), mBypassEffect(false)
{
{
CABundleLocker lock;
if (!sLocalized)
{
CFBundleRef bundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.audio.units.Components") );
if (bundle != NULL)
{
kPanner_Azimuth_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Azimuth_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
kPanner_Elevation_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Elevation_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
kPanner_Distance_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Distance_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
kPanner_CoordScale_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_CoordScale_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
kPanner_RefDistance_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_RefDistance_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
kPanner_Gain_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Gain_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
}
sLocalized = true;
}
}
CreateElements();
SetParameter(kPannerParam_Azimuth, kPannerParamDefault_Azimuth);
SetParameter(kPannerParam_Elevation, kPannerParamDefault_Elevation);
SetParameter(kPannerParam_Distance, kPannerParamDefault_Distance);
SetParameter(kPannerParam_CoordScale, kPannerParamDefault_CoordScale);
SetParameter(kPannerParam_RefDistance, kPannerParamDefault_RefDistance);
SetParameter(kPannerParam_Gain, kPannerParamDefault_Gain);
}
//_____________________________________________________________________________
//
AUPannerBase::~AUPannerBase()
{
Cleanup();
}
//_____________________________________________________________________________
//
/*! @method Initialize */
OSStatus AUPannerBase::Initialize()
{
OSStatus err = noErr;
AllocBypassMatrix();
err = UpdateBypassMatrix();
return err;
}
//_____________________________________________________________________________
//
/*! @method AllocBypassMatrix */
void AUPannerBase::AllocBypassMatrix()
{
UInt32 inChannels = GetNumberOfInputChannels();
UInt32 outChannels = GetNumberOfOutputChannels();
mBypassMatrix.alloc(inChannels * outChannels, true);
}
static AudioChannelLayoutTag DefaultTagForNumberOfChannels(UInt32 inNumberChannels)
{
switch (inNumberChannels) {
case 1: return kAudioChannelLayoutTag_Mono;
case 2: return kAudioChannelLayoutTag_Stereo;
case 4: return kAudioChannelLayoutTag_Quadraphonic;
case 5: return kAudioChannelLayoutTag_AudioUnit_5_0;
case 6: return kAudioChannelLayoutTag_AudioUnit_6_0;
case 7: return kAudioChannelLayoutTag_AudioUnit_7_0;
case 8: return kAudioChannelLayoutTag_AudioUnit_8;
default: return 0xFFFF0000 | inNumberChannels;
}
}
//_____________________________________________________________________________
//
/*! @method UpdateBypassMatrix */
OSStatus AUPannerBase::SetDefaultChannelLayoutsIfNone()
{
OSStatus err = noErr;
// if layout has not been set, then guess layout from number of channels
UInt32 inChannels = GetNumberOfInputChannels();
AudioChannelLayout inputLayoutSubstitute;
const AudioChannelLayout* inputLayout = &GetInputLayout();
if (inputLayout == NULL || inputLayout->mChannelLayoutTag == 0) {
inputLayout = &inputLayoutSubstitute;
inputLayoutSubstitute.mNumberChannelDescriptions = 0;
inputLayoutSubstitute.mChannelBitmap = 0;
inputLayoutSubstitute.mChannelLayoutTag = DefaultTagForNumberOfChannels(inChannels);
mInputLayout = &inputLayoutSubstitute;
err = SetAudioChannelLayout(kAudioUnitScope_Input, 0, &GetInputLayout());
if (err) return err;
}
// if layout has not been set, then guess layout from number of channels
UInt32 outChannels = GetNumberOfOutputChannels();
AudioChannelLayout outputLayoutSubstitute;
const AudioChannelLayout* outputLayout = &GetOutputLayout();
if (outputLayout == NULL || outputLayout->mChannelLayoutTag == 0) {
outputLayout = &outputLayoutSubstitute;
outputLayoutSubstitute.mNumberChannelDescriptions = 0;
outputLayoutSubstitute.mChannelBitmap = 0;
outputLayoutSubstitute.mChannelLayoutTag = DefaultTagForNumberOfChannels(outChannels);
mOutputLayout = &outputLayoutSubstitute;
err = SetAudioChannelLayout(kAudioUnitScope_Output, 0, &GetOutputLayout());
if (err) return err;
}
return err;
}
OSStatus AUPannerBase::UpdateBypassMatrix()
{
OSStatus err = SetDefaultChannelLayoutsIfNone();
if (err) return err;
UInt32 inChannels = GetNumberOfInputChannels();
UInt32 outChannels = GetNumberOfOutputChannels();
const AudioChannelLayout* inoutACL[2];
inoutACL[0] = &GetInputLayout();
inoutACL[1] = &GetOutputLayout();
mBypassMatrix.alloc(inChannels * outChannels, true);
UInt32 propSize = inChannels * outChannels * sizeof(Float32);
err = AudioFormatGetProperty(kAudioFormatProperty_MatrixMixMap, sizeof(inoutACL), inoutACL, &propSize, mBypassMatrix());
if (err) {
// if there is an error, use a diagonal matrix.
Float32* bypass = mBypassMatrix();
for (UInt32 chan = 0; chan < std::min(inChannels, outChannels); ++chan)
{
float *amp = bypass + (chan * outChannels + chan);
*amp = 1.;
}
}
return noErr;
}
//_____________________________________________________________________________
//
/*! @method Cleanup */
void AUPannerBase::Cleanup()
{
}
//_____________________________________________________________________________
//
/*! @method Reset */
OSStatus AUPannerBase::Reset( AudioUnitScope inScope,
AudioUnitElement inElement)
{
return AUBase::Reset(inScope, inElement);
}
//_____________________________________________________________________________
//
/*! @method GetParameterInfo */
OSStatus AUPannerBase::GetParameterInfo( AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo )
{
OSStatus result = noErr;
outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
+ kAudioUnitParameterFlag_IsReadable;
if (inScope == kAudioUnitScope_Global) {
switch(inParameterID)
{
case kPannerParam_Azimuth:
AUBase::FillInParameterName (outParameterInfo, kPanner_Azimuth_Name, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Degrees;
outParameterInfo.minValue = -180.;
outParameterInfo.maxValue = 180;
outParameterInfo.defaultValue = kPannerParamDefault_Azimuth;
break;
case kPannerParam_Elevation:
AUBase::FillInParameterName (outParameterInfo, kPanner_Elevation_Name, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Degrees;
outParameterInfo.minValue = -90.;
outParameterInfo.maxValue = 90;
outParameterInfo.defaultValue = kPannerParamDefault_Elevation;
break;
case kPannerParam_Distance:
AUBase::FillInParameterName (outParameterInfo, kPanner_Distance_Name, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.minValue = 0.0;
outParameterInfo.maxValue = 1.;
outParameterInfo.defaultValue = kPannerParamDefault_Distance;
outParameterInfo.flags += kAudioUnitParameterFlag_IsHighResolution;
//outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic;
break;
case kPannerParam_CoordScale:
AUBase::FillInParameterName (outParameterInfo, kPanner_CoordScale_Name, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Meters;
outParameterInfo.minValue = 0.01;
outParameterInfo.maxValue = 1000.;
outParameterInfo.defaultValue = kPannerParamDefault_CoordScale;
outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic;
break;
case kPannerParam_RefDistance:
AUBase::FillInParameterName (outParameterInfo, kPanner_RefDistance_Name, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Meters;
outParameterInfo.minValue = 0.01;
outParameterInfo.maxValue = 1000.;
outParameterInfo.defaultValue = kPannerParamDefault_RefDistance;
outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic;
break;
case kPannerParam_Gain:
AUBase::FillInParameterName (outParameterInfo, kPanner_Gain_Name, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.minValue = 0.;
outParameterInfo.maxValue = 1.;
outParameterInfo.defaultValue = kPannerParamDefault_Gain;
break;
default:
result = kAudioUnitErr_InvalidParameter;
break;
}
} else {
result = kAudioUnitErr_InvalidParameter;
}
return result;
}
//_____________________________________________________________________________
//
OSStatus AUPannerBase::GetParameter( AudioUnitParameterID inParamID,
AudioUnitScope inScope,
AudioUnitElement inElement,
Float32 & outValue)
{
if (inScope != kAudioUnitScope_Global)
return kAudioUnitErr_InvalidScope;
outValue = Globals()->GetParameter(inParamID);
return noErr;
}
//_____________________________________________________________________________
//
OSStatus AUPannerBase::SetParameter( AudioUnitParameterID inParamID,
AudioUnitScope inScope,
AudioUnitElement inElement,
Float32 inValue,
UInt32 inBufferOffsetInFrames)
{
if (inScope != kAudioUnitScope_Global)
return kAudioUnitErr_InvalidScope;
Globals()->SetParameter(inParamID, inValue);
return noErr;
}
//_____________________________________________________________________________
//
/*! @method GetPropertyInfo */
OSStatus AUPannerBase::GetPropertyInfo (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
OSStatus err = noErr;
switch (inID) {
case kAudioUnitProperty_BypassEffect:
if (inScope != kAudioUnitScope_Global)
return kAudioUnitErr_InvalidScope;
outWritable = true;
outDataSize = sizeof (UInt32);
break;
default:
err = AUBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
}
return err;
}
//_____________________________________________________________________________
//
/*! @method GetProperty */
OSStatus AUPannerBase::GetProperty (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
OSStatus err = noErr;
switch (inID)
{
case kAudioUnitProperty_BypassEffect:
if (inScope != kAudioUnitScope_Global)
return kAudioUnitErr_InvalidScope;
*((UInt32*)outData) = (IsBypassEffect() ? 1 : 0);
break;
default:
err = AUBase::GetProperty(inID, inScope, inElement, outData);
}
return err;
}
//_____________________________________________________________________________
//
/*! @method SetProperty */
OSStatus AUPannerBase::SetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
switch (inID)
{
case kAudioUnitProperty_BypassEffect:
if (inDataSize < sizeof(UInt32))
return kAudioUnitErr_InvalidPropertyValue;
bool tempNewSetting = *((UInt32*)inData) != 0;
// we're changing the state of bypass
if (tempNewSetting != IsBypassEffect())
{
if (!tempNewSetting && IsBypassEffect() && IsInitialized()) // turning bypass off and we're initialized
Reset(0, 0);
SetBypassEffect (tempNewSetting);
}
return noErr;
}
return AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize);
}
//_____________________________________________________________________________
//
/*! @method StreamFormatWritable */
bool AUPannerBase::StreamFormatWritable (AudioUnitScope scope,
AudioUnitElement element)
{
return true;
}
//_____________________________________________________________________________
//
/*! @method ChangeStreamFormat */
OSStatus AUPannerBase::ChangeStreamFormat (
AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inPrevFormat,
const CAStreamBasicDescription & inNewFormat)
{
if (inScope == kAudioUnitScope_Input && !InputChannelConfigIsSupported(inNewFormat.NumberChannels()))
return kAudioUnitErr_FormatNotSupported;
if (inScope == kAudioUnitScope_Output && !OutputChannelConfigIsSupported(inNewFormat.NumberChannels()))
return kAudioUnitErr_FormatNotSupported;
if (inNewFormat.NumberChannels() != inPrevFormat.NumberChannels())
RemoveAudioChannelLayout(inScope, inElement);
return AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat);
}
//_____________________________________________________________________________
//
/*! @method Render */
OSStatus AUPannerBase::Render(AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames)
{
if (IsBypassEffect())
return BypassRender(ioActionFlags, inTimeStamp, inNumberFrames);
else
return PannerRender(ioActionFlags, inTimeStamp, inNumberFrames);
}
//_____________________________________________________________________________
//
/*! @method Render */
OSStatus AUPannerBase::BypassRender(AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames)
{
AudioUnitRenderActionFlags xflags = 0;
OSStatus result = PullInput(0, xflags, inTimeStamp, inNumberFrames);
if (result) return false;
bool isSilent = xflags & kAudioUnitRenderAction_OutputIsSilence;
AudioBufferList& outputBufferList = GetOutput(0)->GetBufferList();
AUBufferList::ZeroBuffer(outputBufferList);
if (!isSilent)
{
UInt32 inChannels = GetNumberOfInputChannels();
UInt32 outChannels = GetNumberOfOutputChannels();
Float32* bypass = mBypassMatrix();
for (UInt32 outChan = 0; outChan < outChannels; ++outChan)
{
float* outData = GetOutput(0)->GetChannelData(outChan);
for (UInt32 inChan = 0; inChan < inChannels; ++inChan)
{
float* inData = GetInput(0)->GetChannelData(inChan);
float *amp = bypass + (inChan * outChannels + outChan);
vDSP_vsma(inData, 1, amp, outData, 1, outData, 1, inNumberFrames);
}
}
}
return noErr;
}
//_____________________________________________________________________________
//
UInt32 AUPannerBase::GetAudioChannelLayout( AudioUnitScope inScope,
AudioUnitElement inElement,
AudioChannelLayout * outLayoutPtr,
Boolean & outWritable)
{
SetDefaultChannelLayoutsIfNone();
outWritable = true;
CAAudioChannelLayout* caacl = NULL;
switch (inScope)
{
case kAudioUnitScope_Input:
caacl = &mInputLayout;
break;
case kAudioUnitScope_Output:
caacl = &mOutputLayout;
break;
default:
COMPONENT_THROW(kAudioUnitErr_InvalidScope);
}
if (inElement != 0)
COMPONENT_THROW(kAudioUnitErr_InvalidElement);
UInt32 size = caacl->IsValid() ? caacl->Size() : 0;
if (size > 0 && outLayoutPtr)
memcpy(outLayoutPtr, &caacl->Layout(), size);
return size;
}
//_____________________________________________________________________________
//
OSStatus AUPannerBase::RemoveAudioChannelLayout( AudioUnitScope inScope,
AudioUnitElement inElement)
{
CAAudioChannelLayout* caacl = NULL;
switch (inScope)
{
case kAudioUnitScope_Input:
caacl = &mInputLayout;
break;
case kAudioUnitScope_Output:
caacl = &mOutputLayout;
break;
default:
return kAudioUnitErr_InvalidScope;
}
if (inElement != 0)
return kAudioUnitErr_InvalidElement;
*caacl = NULL;
return noErr;
}
//_____________________________________________________________________________
//
OSStatus AUPannerBase::SetAudioChannelLayout( AudioUnitScope inScope,
AudioUnitElement inElement,
const AudioChannelLayout * inLayout)
{
if (!inLayout)
return RemoveAudioChannelLayout(inScope, inElement);
if (!ChannelLayoutTagIsSupported(inScope, inElement, inLayout->mChannelLayoutTag))
return kAudioUnitErr_FormatNotSupported;
CAAudioChannelLayout* caacl = NULL;
UInt32 currentChannels;
switch (inScope)
{
case kAudioUnitScope_Input:
caacl = &mInputLayout;
currentChannels = GetNumberOfInputChannels();
break;
case kAudioUnitScope_Output:
caacl = &mOutputLayout;
currentChannels = GetNumberOfOutputChannels();
break;
default:
return kAudioUnitErr_InvalidScope;
}
if (inElement != 0)
return kAudioUnitErr_InvalidElement;
UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout);
if (currentChannels != numChannelsInLayout)
return kAudioUnitErr_InvalidPropertyValue;
*caacl = inLayout;
if (IsInitialized())
UpdateBypassMatrix();
return noErr;
}
//_____________________________________________________________________________
//
UInt32 AUPannerBase::GetChannelLayoutTags( AudioUnitScope inScope,
AudioUnitElement inElement,
AudioChannelLayoutTag* outTags)
{
switch (inScope)
{
case kAudioUnitScope_Input:
if (outTags) {
outTags[0] = kAudioChannelLayoutTag_Mono;
outTags[1] = kAudioChannelLayoutTag_Stereo;
outTags[2] = kAudioChannelLayoutTag_Ambisonic_B_Format;
}
return 3;
case kAudioUnitScope_Output:
if (outTags) {
outTags[0] = kAudioChannelLayoutTag_Stereo;
outTags[1] = kAudioChannelLayoutTag_Quadraphonic;
outTags[2] = kAudioChannelLayoutTag_AudioUnit_5_0;
outTags[3] = kAudioChannelLayoutTag_AudioUnit_6_0;
outTags[4] = kAudioChannelLayoutTag_AudioUnit_7_0;
outTags[5] = kAudioChannelLayoutTag_AudioUnit_7_0_Front;
outTags[6] = kAudioChannelLayoutTag_AudioUnit_8;
}
return 7;
default: {
OSStatus err = kAudioUnitErr_InvalidScope;
throw err;
}
}
}
//_____________________________________________________________________________
//
bool AUPannerBase::ChannelConfigIsSupported()
{
UInt32 inChannels = GetNumberOfInputChannels();
UInt32 outChannels = GetNumberOfOutputChannels();
const AUChannelInfo* cinfo = NULL;
UInt32 numConfigs = SupportedNumChannels(&cinfo);
for (UInt32 i = 0; i < numConfigs; ++i)
{
if (cinfo[i].inChannels == (SInt16)inChannels && cinfo[i].outChannels == (SInt16)outChannels)
return true;
}
return false;
}
//_____________________________________________________________________________
//
bool AUPannerBase::InputChannelConfigIsSupported(UInt32 inNumberChannels)
{
const AUChannelInfo* cinfo = NULL;
UInt32 numConfigs = SupportedNumChannels(&cinfo);
for (UInt32 i = 0; i < numConfigs; ++i)
{
if (cinfo[i].inChannels == (SInt16)inNumberChannels)
return true;
}
return false;
}
//_____________________________________________________________________________
//
bool AUPannerBase::OutputChannelConfigIsSupported(UInt32 inNumberChannels)
{
const AUChannelInfo* cinfo = NULL;
UInt32 numConfigs = SupportedNumChannels(&cinfo);
for (UInt32 i = 0; i < numConfigs; ++i)
{
if (cinfo[i].outChannels == (SInt16)inNumberChannels)
return true;
}
return false;
}
//_____________________________________________________________________________
//
bool AUPannerBase::ChannelLayoutTagIsSupported( AudioUnitScope inScope,
AudioUnitElement inElement,
AudioChannelLayoutTag inTag)
{
UInt32 numTags = GetChannelLayoutTags(inScope, inElement, NULL);
CAAutoFree<AudioChannelLayoutTag> tags(numTags);
GetChannelLayoutTags(inScope, inElement, tags());
for (UInt32 i = 0; i < numTags; ++i)
{
if (tags[i] == inTag)
return true;
}
return false;
}

View File

@@ -0,0 +1,272 @@
/*
File: AUPannerBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUPannerBase_h__
#define __AUPannerBase_h__
#include "AUBase.h"
#include <math.h>
#include "CAAutoDisposer.h"
#include "CAAudioChannelLayout.h"
/*! @class AUPannerBase */
class AUPannerBase : public AUBase
{
public:
/*! @ctor AUPannerBase */
AUPannerBase(AudioComponentInstance inAudioUnit);
/*! @dtor ~AUPannerBase */
virtual ~AUPannerBase();
/*! @method Initialize */
virtual OSStatus Initialize();
/*! @method Cleanup */
virtual void Cleanup();
/*! @method Reset */
virtual OSStatus Reset( AudioUnitScope inScope,
AudioUnitElement inElement);
/*! @method CanScheduleParameters */
virtual bool CanScheduleParameters() const { return false; }
/*! @method GetParameterInfo */
virtual OSStatus GetParameterInfo( AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo &outParameterInfo );
/*! @method GetPropertyInfo */
virtual OSStatus GetPropertyInfo (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable);
/*! @method GetProperty */
virtual OSStatus GetProperty (AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
/*! @method SetProperty */
virtual OSStatus SetProperty(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize);
/*! @method StreamFormatWritable */
virtual bool StreamFormatWritable (AudioUnitScope scope,
AudioUnitElement element);
/*! @method ChangeStreamFormat */
virtual OSStatus ChangeStreamFormat (
AudioUnitScope inScope,
AudioUnitElement inElement,
const CAStreamBasicDescription & inPrevFormat,
const CAStreamBasicDescription & inNewFormat);
/*! @method IsBypassEffect */
// This is used for the property value - to reflect to the UI if an effect is bypassed
bool IsBypassEffect () { return mBypassEffect; }
/*! @method SetBypassEffect */
virtual void SetBypassEffect (bool inFlag) { mBypassEffect = inFlag; }
/*! @method Render */
virtual OSStatus Render(AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames);
/*! @method Render */
virtual OSStatus PannerRender(AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames) = 0;
/*! @method BypassRender */
virtual OSStatus BypassRender(AudioUnitRenderActionFlags & ioActionFlags,
const AudioTimeStamp & inTimeStamp,
UInt32 inNumberFrames);
/*! @method GetAudioChannelLayout */
virtual UInt32 GetAudioChannelLayout( AudioUnitScope inScope,
AudioUnitElement inElement,
AudioChannelLayout * outLayoutPtr,
Boolean & outWritable);
/*! @method SetAudioChannelLayout */
virtual OSStatus SetAudioChannelLayout( AudioUnitScope inScope,
AudioUnitElement inElement,
const AudioChannelLayout * inLayout);
/*! @method RemoveAudioChannelLayout */
virtual OSStatus RemoveAudioChannelLayout( AudioUnitScope inScope,
AudioUnitElement inElement);
/*! @method GetChannelLayoutTags */
virtual UInt32 GetChannelLayoutTags( AudioUnitScope inScope,
AudioUnitElement inElement,
AudioChannelLayoutTag* outTags);
/*! @method GetNumberOfInputChannels */
UInt32 GetNumberOfInputChannels() { return ((AUIOElement*)Inputs().SafeGetElement(0))->NumberChannels(); };
/*! @method GetNumberOfOutputChannels */
UInt32 GetNumberOfOutputChannels() { return ((AUIOElement*)Outputs().SafeGetElement(0))->NumberChannels(); }
/*! @method GetParameter */
virtual OSStatus GetParameter( AudioUnitParameterID inParamID,
AudioUnitScope inScope,
AudioUnitElement inElement,
Float32 & outValue);
/*! @method SetParameter */
virtual OSStatus SetParameter( AudioUnitParameterID inParamID,
AudioUnitScope inScope,
AudioUnitElement inElement,
Float32 inValue,
UInt32 inBufferOffsetInFrames);
// convenience wrappers for accessing parameters in the global scope
/*! @method SetParameter */
void SetParameter( UInt32 inParamID,
Float32 inValue)
{
OSStatus err = SetParameter(inParamID, kAudioUnitScope_Global, 0, inValue, 0);
if (err) throw err;
}
/*! @method GetParameter */
Float32 GetParameter( UInt32 inParamID )
{
Float32 outValue = 0.;
OSStatus err = GetParameter(inParamID, kAudioUnitScope_Global, 0, outValue);
if (err) throw err;
return outValue;
}
/*! @method InputChannelConfigIsSupported */
bool InputChannelConfigIsSupported(UInt32 inNumberChannels);
/*! @method OutputChannelConfigIsSupported */
bool OutputChannelConfigIsSupported(UInt32 inNumberChannels);
/*! @method ChannelConfigIsSupported */
bool ChannelConfigIsSupported();
/*! @method SupportsTail */
virtual bool SupportsTail () { return true; }
/*! @method GetTailTime */
virtual Float64 GetTailTime() { return 0; }
/*! @method GetGain */
Float32 GetGain() { return GetParameter(kPannerParam_Gain); }
/*! @method GetTailTime */
Float32 GetAzimuth() { return GetParameter(kPannerParam_Azimuth); }
/*! @method GetElevation */
Float32 GetElevation() { return GetParameter(kPannerParam_Elevation); }
/*! @method GetDistance */
Float32 GetDistance() { return GetParameter(kPannerParam_Distance); }
/*! @method GetCoordScale */
Float32 GetCoordScale() { return GetParameter(kPannerParam_CoordScale); }
/*! @method GetRefDistance */
Float32 GetRefDistance() { return GetParameter(kPannerParam_RefDistance); }
/*! @method SetGain */
void SetGain(Float32 inValue) { SetParameter(kPannerParam_Gain, inValue); }
/*! @method SetAzimuth */
void SetAzimuth(Float32 inValue) { SetParameter(kPannerParam_Azimuth, inValue); }
/*! @method SetElevation */
void SetElevation(Float32 inValue) { SetParameter(kPannerParam_Elevation, inValue); }
/*! @method SetDistance */
void SetDistance(Float32 inValue) { SetParameter(kPannerParam_Distance, inValue); }
/*! @method SetCoordScale */
void SetCoordScale(Float32 inValue) { SetParameter(kPannerParam_CoordScale, inValue); }
/*! @method SetRefDistance */
void SetRefDistance(Float32 inValue) { SetParameter(kPannerParam_RefDistance, inValue); }
protected:
/*! @method ShouldBypassEffect */
// This is used in the render call to see if an effect is bypassed
// It can return a different status than IsBypassEffect (though it MUST take that into account)
virtual bool ShouldBypassEffect () { return IsBypassEffect(); }
/*! @method AllocBypassMatrix */
void AllocBypassMatrix();
/*! @method UpdateBypassMatrix */
OSStatus UpdateBypassMatrix();
/*! @method SetDefaultChannelLayoutsIfNone */
OSStatus SetDefaultChannelLayoutsIfNone();
/*! @method ChannelLayoutTagIsSupported */
bool ChannelLayoutTagIsSupported( AudioUnitScope inScope,
AudioUnitElement inElement,
AudioChannelLayoutTag inTag);
const AudioChannelLayout& GetInputLayout() const { return mInputLayout.Layout(); }
const AudioChannelLayout& GetOutputLayout() const { return mOutputLayout.Layout(); }
private:
/*! @var UpdateBypassMatrix */
bool mBypassEffect;
/*! @var mBypassMatrix */
CAAutoFree<Float32> mBypassMatrix;
/*! @var mInputLayout */
CAAudioChannelLayout mInputLayout;
/*! @var mOutputLayout */
CAAudioChannelLayout mOutputLayout;
};
#endif /* __AUPannerBase_h__ */

View File

@@ -0,0 +1,354 @@
/*
File: MusicDeviceBase.cpp
Abstract: MusicDeviceBase.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "MusicDeviceBase.h"
// compatibility with older OS SDK releases
typedef OSStatus
(*TEMP_MusicDeviceMIDIEventProc)( void * inComponentStorage,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame);
typedef OSStatus
(*TEMP_MusicDeviceStartNoteProc)( void * inComponentStorage,
MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams * inParams);
typedef OSStatus
(*TEMP_MusicDeviceStopNoteProc)(void * inComponentStorage,
MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame);
#if !CA_USE_AUDIO_PLUGIN_ONLY
static OSStatus MusicDeviceBaseMIDIEvent(void * inComponentStorage,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame);
static OSStatus MusicDeviceBaseStartNote( void * inComponentStorage,
MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams * inParams);
static OSStatus MusicDeviceBaseStopNote(void * inComponentStorage,
MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame);
#endif
MusicDeviceBase::MusicDeviceBase(AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups)
: AUBase(inInstance, numInputs, numOutputs, numGroups),
AUMIDIBase(this)
{
}
OSStatus MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable)
{
OSStatus result;
switch (inID)
{
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_InstrumentCount:
if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
outDataSize = sizeof(UInt32);
outWritable = false;
result = noErr;
break;
#endif
default:
result = AUBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
if (result == kAudioUnitErr_InvalidProperty)
result = AUMIDIBase::DelegateGetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
break;
}
return result;
}
OSStatus MusicDeviceBase::GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData)
{
OSStatus result;
switch (inID)
{
#if !CA_USE_AUDIO_PLUGIN_ONLY
case kAudioUnitProperty_FastDispatch:
if (!IsCMgrObject()) return kAudioUnitErr_InvalidProperty;
if (inElement == kMusicDeviceMIDIEventSelect) {
*(TEMP_MusicDeviceMIDIEventProc *)outData = MusicDeviceBaseMIDIEvent;
return noErr;
}
else if (inElement == kMusicDeviceStartNoteSelect) {
*(TEMP_MusicDeviceStartNoteProc *)outData = MusicDeviceBaseStartNote;
return noErr;
}
else if (inElement == kMusicDeviceStopNoteSelect) {
*(TEMP_MusicDeviceStopNoteProc *)outData = MusicDeviceBaseStopNote;
return noErr;
}
return kAudioUnitErr_InvalidElement;
#endif
#if !TARGET_OS_IPHONE
case kMusicDeviceProperty_InstrumentCount:
if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
return GetInstrumentCount (*(UInt32*)outData);
#endif
default:
result = AUBase::GetProperty (inID, inScope, inElement, outData);
if (result == kAudioUnitErr_InvalidProperty)
result = AUMIDIBase::DelegateGetProperty (inID, inScope, inElement, outData);
}
return result;
}
OSStatus MusicDeviceBase::SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize)
{
OSStatus result = AUBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
if (result == kAudioUnitErr_InvalidProperty)
result = AUMIDIBase::DelegateSetProperty (inID, inScope, inElement, inData, inDataSize);
return result;
}
// For a MusicDevice that doesn't support separate instruments (ie. is mono-timbral)
// then this call should return an instrument count of zero and noErr
OSStatus MusicDeviceBase::GetInstrumentCount (UInt32 &outInstCount) const
{
outInstCount = 0;
return noErr;
}
OSStatus MusicDeviceBase::HandleNoteOn( UInt8 inChannel,
UInt8 inNoteNumber,
UInt8 inVelocity,
UInt32 inStartFrame)
{
MusicDeviceNoteParams params;
params.argCount = 2;
params.mPitch = inNoteNumber;
params.mVelocity = inVelocity;
return StartNote (kMusicNoteEvent_UseGroupInstrument, inChannel, NULL, inStartFrame, params);
}
OSStatus MusicDeviceBase::HandleNoteOff( UInt8 inChannel,
UInt8 inNoteNumber,
UInt8 inVelocity,
UInt32 inStartFrame)
{
return StopNote (inChannel, inNoteNumber, inStartFrame);
}
OSStatus
MusicDeviceBase::HandleStartNoteMessage (MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams * inParams)
{
if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError;
if (!IsInitialized()) return kAudioUnitErr_Uninitialized;
return StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
}
#if TARGET_OS_MAC
#if __LP64__
// comp instance, parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_index + 1];
#else
// parameters in reverse order, then comp instance
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_nparams - 1 - _index];
#endif
#elif TARGET_OS_WIN32
// (no comp instance), parameters in forward order
#define PARAM(_typ, _name, _index, _nparams) \
_typ _name = *(_typ *)&params->params[_index];
#endif
#if !CA_USE_AUDIO_PLUGIN_ONLY
OSStatus MusicDeviceBase::ComponentEntryDispatch( ComponentParameters * params,
MusicDeviceBase * This)
{
if (This == NULL) return kAudio_ParamError;
OSStatus result;
switch (params->what) {
case kMusicDeviceMIDIEventSelect:
case kMusicDeviceSysExSelect:
{
result = AUMIDIBase::ComponentEntryDispatch (params, This);
}
break;
case kMusicDevicePrepareInstrumentSelect:
{
PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1);
result = This->PrepareInstrument(inInstrument);
}
break;
case kMusicDeviceReleaseInstrumentSelect:
{
PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1);
result = This->ReleaseInstrument(inInstrument);
}
break;
case kMusicDeviceStartNoteSelect:
{
PARAM(MusicDeviceInstrumentID, pbinInstrument, 0, 5);
PARAM(MusicDeviceGroupID, pbinGroupID, 1, 5);
PARAM(NoteInstanceID *, pboutNoteInstanceID, 2, 5);
PARAM(UInt32, pbinOffsetSampleFrame, 3, 5);
PARAM(const MusicDeviceNoteParams *, pbinParams, 4, 5);
result = This->HandleStartNoteMessage(pbinInstrument, pbinGroupID, pboutNoteInstanceID, pbinOffsetSampleFrame, pbinParams);
}
break;
case kMusicDeviceStopNoteSelect:
{
PARAM(MusicDeviceGroupID, pbinGroupID, 0, 3);
PARAM(NoteInstanceID, pbinNoteInstanceID, 1, 3);
PARAM(UInt32, pbinOffsetSampleFrame, 2, 3);
result = This->StopNote(pbinGroupID, pbinNoteInstanceID, pbinOffsetSampleFrame);
}
break;
default:
result = AUBase::ComponentEntryDispatch(params, This);
break;
}
return result;
}
#endif
#if !CA_USE_AUDIO_PLUGIN_ONLY
// fast dispatch
static OSStatus MusicDeviceBaseMIDIEvent(void * inComponentStorage,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame)
{
OSStatus result = noErr;
try {
MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
if (This == NULL) return kAudio_ParamError;
result = This->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
}
COMPONENT_CATCH
return result;
}
OSStatus MusicDeviceBaseStartNote( void * inComponentStorage,
MusicDeviceInstrumentID inInstrument,
MusicDeviceGroupID inGroupID,
NoteInstanceID * outNoteInstanceID,
UInt32 inOffsetSampleFrame,
const MusicDeviceNoteParams * inParams)
{
OSStatus result = noErr;
try {
if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError;
MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
if (This == NULL) return kAudio_ParamError;
result = This->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
}
COMPONENT_CATCH
return result;
}
OSStatus MusicDeviceBaseStopNote(void * inComponentStorage,
MusicDeviceGroupID inGroupID,
NoteInstanceID inNoteInstanceID,
UInt32 inOffsetSampleFrame)
{
OSStatus result = noErr;
try {
MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
if (This == NULL) return kAudio_ParamError;
result = This->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);
}
COMPONENT_CATCH
return result;
}
#endif

View File

@@ -0,0 +1,126 @@
/*
File: MusicDeviceBase.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __MusicDeviceBase_h__
#define __MusicDeviceBase_h__
#include "AUMIDIBase.h"
// ________________________________________________________________________
// MusicDeviceBase
//
/*! @class MusicDeviceBase */
class MusicDeviceBase : public AUBase, public AUMIDIBase {
public:
/*! @ctor MusicDeviceBase */
MusicDeviceBase( AudioComponentInstance inInstance,
UInt32 numInputs,
UInt32 numOutputs,
UInt32 numGroups = 0);
virtual OSStatus MIDIEvent( UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame)
{
return AUMIDIBase::MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame);
}
/*! @method SysEx */
virtual OSStatus SysEx( const UInt8 * inData,
UInt32 inLength)
{
return AUMIDIBase::SysEx (inData, inLength);
}
/*! @method GetPropertyInfo */
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
UInt32 & outDataSize,
Boolean & outWritable);
/*! @method GetProperty */
virtual OSStatus GetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
/*! @method SetProperty */
virtual OSStatus SetProperty( AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * inData,
UInt32 inDataSize);
/*! @method HandleNoteOn */
virtual OSStatus HandleNoteOn( UInt8 inChannel,
UInt8 inNoteNumber,
UInt8 inVelocity,
UInt32 inStartFrame);
/*! @method HandleNoteOff */
virtual OSStatus HandleNoteOff( UInt8 inChannel,
UInt8 inNoteNumber,
UInt8 inVelocity,
UInt32 inStartFrame);
/*! @method GetInstrumentCount */
virtual OSStatus GetInstrumentCount ( UInt32 &outInstCount) const;
#if !CA_USE_AUDIO_PLUGIN_ONLY
// component dispatcher
/*! @method ComponentEntryDispatch */
static OSStatus ComponentEntryDispatch( ComponentParameters * params,
MusicDeviceBase * This);
#endif
private:
OSStatus HandleStartNoteMessage (MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams);
};
#endif // __MusicDeviceBase_h__

View File

@@ -0,0 +1,125 @@
/*
File: AUBaseHelper.cpp
Abstract: AUBaseHelper.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUBaseHelper.h"
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AudioUnitProperties.h>
#else
#include <AudioUnitProperties.h>
#endif
OSStatus GetFileRefPath (CFDictionaryRef parent, CFStringRef frKey, CFStringRef * fPath)
{
static CFStringRef kFRString = CFSTR (kAUPresetExternalFileRefs);
const void* frVal = CFDictionaryGetValue(parent, kFRString);
if (!frVal) return kAudioUnitErr_InvalidPropertyValue;
const void* frString = CFDictionaryGetValue ((CFDictionaryRef)frVal, frKey);
if (!frString) return kAudioUnitErr_InvalidPropertyValue;
if (fPath)
*fPath = (CFStringRef)frString;
return noErr;
}
CFMutableDictionaryRef CreateFileRefDict (CFStringRef fKey, CFStringRef fPath, CFMutableDictionaryRef fileRefDict)
{
if (!fileRefDict)
fileRefDict = CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue (fileRefDict, fKey, fPath);
return fileRefDict;
}
#if TARGET_OS_MAC
// check if the URL can be accessed for reading/writing. Returns 0 if yes, or the error value.
int AccessURLAsset(const CFURLRef inURL, int mode)
{
char path[PATH_MAX];
if (CFURLGetFileSystemRepresentation(inURL, TRUE, (UInt8 *)path, PATH_MAX) == FALSE)
return kAudio_FileNotFoundError;
// check whether we have access
int ret = access(path, mode);
// syslog(LOG_CRIT, "access() error is %d for \"%s\".\n", ret, path);
if (ret == 0) return 0;
switch (errno) {
case EACCES:
case EPERM:
return -54; /*permission denied error*/
case ENOENT:
case ENOTDIR:
case ELOOP:
return kAudio_FileNotFoundError;
default:
return errno;
}
}
#endif
#if DEBUG
//_____________________________________________________________________________
//
void PrintAUParamEvent (AudioUnitParameterEvent& event, FILE* f)
{
bool isRamp = event.eventType == kParameterEvent_Ramped;
fprintf (f, "\tParamID=%ld,Scope=%ld,Element=%ld\n", (long)event.parameter, (long)event.scope, (long)event.element);
fprintf (f, "\tEvent Type:%s,", (isRamp ? "ramp" : "immediate"));
if (isRamp)
fprintf (f, "start=%ld,dur=%ld,startValue=%f,endValue=%f\n",
(long)event.eventValues.ramp.startBufferOffset, (long)event.eventValues.ramp.durationInFrames,
event.eventValues.ramp.startValue, event.eventValues.ramp.endValue);
else
fprintf (f, "start=%ld,value=%f\n",
(long)event.eventValues.immediate.bufferOffset,
event.eventValues.immediate.value);
fprintf (f, "- - - - - - - - - - - - - - - -\n");
}
#endif

View File

@@ -0,0 +1,75 @@
/*
File: AUBaseHelper.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUBaseHelper_h__
#define __AUBaseHelper_h__
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreFoundation/CoreFoundation.h>
#include <AudioUnit/AUComponent.h>
#else
#include <CoreFoundation.h>
#include <AUComponent.h>
#endif
#include "AUBase.h"
// helpers for dealing with the file-references dictionary in an AUPreset
OSStatus GetFileRefPath (CFDictionaryRef parent, CFStringRef frKey, CFStringRef * fPath);
// if fileRefDict is NULL, this call creates one
// if not NULL, then the key value is added to it
CFMutableDictionaryRef CreateFileRefDict (CFStringRef fKey, CFStringRef fPath, CFMutableDictionaryRef fileRefDict);
int AccessURLAsset(const CFURLRef inURL, int mode);
#if DEBUG
void PrintAUParamEvent (AudioUnitParameterEvent& event, FILE* f);
#endif
#endif // __AUBaseHelper_h__

View File

@@ -0,0 +1,219 @@
/*
File: AUBuffer.cpp
Abstract: AUBuffer.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUBuffer.h"
#include <stdlib.h>
AUBufferList::~AUBufferList()
{
Deallocate();
if (mPtrs)
free(mPtrs);
}
// a * b + c
static UInt32 SafeMultiplyAddUInt32(UInt32 a, UInt32 b, UInt32 c)
{
if (a == 0 || b == 0) return c; // prevent zero divide
if (a > (0xFFFFFFFF - c) / b)
throw std::bad_alloc();
return a * b + c;
}
void AUBufferList::Allocate(const CAStreamBasicDescription &format, UInt32 nFrames)
{
UInt32 nStreams;
if (format.IsInterleaved()) {
nStreams = 1;
} else {
nStreams = format.mChannelsPerFrame;
}
// careful -- the I/O thread could be running!
if (nStreams > mAllocatedStreams) {
size_t theHeaderSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);
mPtrs = (AudioBufferList *)CA_realloc(mPtrs,
SafeMultiplyAddUInt32(nStreams, sizeof(AudioBuffer), theHeaderSize));
mAllocatedStreams = nStreams;
}
UInt32 bytesPerStream = SafeMultiplyAddUInt32(nFrames, format.mBytesPerFrame, 0xF) & ~0xF;
UInt32 nBytes = SafeMultiplyAddUInt32(nStreams, bytesPerStream, 0);
if (nBytes > mAllocatedBytes) {
if (mExternalMemory) {
mExternalMemory = false;
mMemory = NULL;
}
mMemory = (Byte *)CA_realloc(mMemory, nBytes);
mAllocatedBytes = nBytes;
}
mAllocatedFrames = nFrames;
mPtrState = kPtrsInvalid;
}
void AUBufferList::Deallocate()
{
mAllocatedStreams = 0;
mAllocatedFrames = 0;
mAllocatedBytes = 0;
// this causes a world of hurt if someone upstream disconnects during I/O (SysSoundGraph)
/* if (mPtrs) {
printf("deallocating bufferlist %08X\n", int(mPtrs));
free(mPtrs);
mPtrs = NULL;
} */
if (mMemory) {
if (mExternalMemory)
mExternalMemory = false;
else
free(mMemory);
mMemory = NULL;
}
mPtrState = kPtrsInvalid;
}
AudioBufferList & AUBufferList::PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames)
{
if (nFrames > mAllocatedFrames)
COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess);
UInt32 nStreams;
UInt32 channelsPerStream;
if (format.IsInterleaved()) {
nStreams = 1;
channelsPerStream = format.mChannelsPerFrame;
} else {
nStreams = format.mChannelsPerFrame;
channelsPerStream = 1;
if (nStreams > mAllocatedStreams)
COMPONENT_THROW(kAudioUnitErr_FormatNotSupported);
}
AudioBufferList *abl = mPtrs;
abl->mNumberBuffers = nStreams;
AudioBuffer *buf = abl->mBuffers;
Byte *mem = mMemory;
UInt32 streamInterval = (mAllocatedFrames * format.mBytesPerFrame + 0xF) & ~0xF;
UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame;
for ( ; nStreams--; ++buf) {
buf->mNumberChannels = channelsPerStream;
buf->mData = mem;
buf->mDataByteSize = bytesPerBuffer;
mem += streamInterval;
}
if (UInt32(mem - mMemory) > mAllocatedBytes)
COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess);
mPtrState = kPtrsToMyMemory;
return *mPtrs;
}
AudioBufferList & AUBufferList::PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames)
{
UInt32 nStreams;
UInt32 channelsPerStream;
if (format.IsInterleaved()) {
nStreams = 1;
channelsPerStream = format.mChannelsPerFrame;
} else {
nStreams = format.mChannelsPerFrame;
channelsPerStream = 1;
if (nStreams > mAllocatedStreams)
COMPONENT_THROW(kAudioUnitErr_FormatNotSupported);
}
AudioBufferList *abl = mPtrs;
abl->mNumberBuffers = nStreams;
AudioBuffer *buf = abl->mBuffers;
UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame;
for ( ; nStreams--; ++buf) {
buf->mNumberChannels = channelsPerStream;
buf->mData = NULL;
buf->mDataByteSize = bytesPerBuffer;
}
mPtrState = kPtrsToExternalMemory;
return *mPtrs;
}
// this should NOT be called while I/O is in process
void AUBufferList::UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf)
{
UInt32 alignedSize = buf.size & ~0xF;
if (mMemory != NULL && alignedSize >= mAllocatedBytes) {
// don't accept the buffer if we already have one and it's big enough
// if we don't already have one, we don't need one
Byte *oldMemory = mMemory;
mMemory = buf.buffer;
mAllocatedBytes = alignedSize;
// from Allocate(): nBytes = nStreams * nFrames * format.mBytesPerFrame;
// thus: nFrames = nBytes / (nStreams * format.mBytesPerFrame)
mAllocatedFrames = mAllocatedBytes / (format.NumberChannelStreams() * format.mBytesPerFrame);
mExternalMemory = true;
free(oldMemory);
}
}
#if DEBUG
void AUBufferList::PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames, bool asFloats)
{
printf(" %s [%d] 0x%08lX:\n", label, subscript, long(&abl));
const AudioBuffer *buf = abl.mBuffers;
for (UInt32 i = 0; i < abl.mNumberBuffers; ++buf, ++i) {
printf(" [%2d] %5dbytes %dch @ %p: ", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData);
if (buf->mData != NULL) {
UInt32 nSamples = nFrames * buf->mNumberChannels;
for (UInt32 j = 0; j < nSamples; ++j) {
if (nSamples > 16 && (j % 16) == 0)
printf("\n\t");
if (asFloats)
printf(" %6.3f", ((float *)buf->mData)[j]);
else
printf(" %08X", (unsigned)((UInt32 *)buf->mData)[j]);
}
}
printf("\n");
}
}
#endif

View File

@@ -0,0 +1,267 @@
/*
File: AUBuffer.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUBuffer_h__
#define __AUBuffer_h__
#include <TargetConditionals.h>
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AudioUnit.h>
#else
#include <AudioUnit.h>
#endif
#include <string.h>
#include "CAStreamBasicDescription.h"
#include "CAAutoDisposer.h"
#include "CADebugMacros.h"
// make this usable outside the stricter context of AudiUnits
#ifndef COMPONENT_THROW
#define COMPONENT_THROW(err) \
do { DebugMessage(#err); throw static_cast<OSStatus>(err); } while (0)
#endif
/*! @class AUBufferList */
class AUBufferList {
enum EPtrState {
kPtrsInvalid,
kPtrsToMyMemory,
kPtrsToExternalMemory
};
public:
/*! @ctor AUBufferList */
AUBufferList() : mPtrState(kPtrsInvalid), mExternalMemory(false), mPtrs(NULL), mMemory(NULL),
mAllocatedStreams(0), mAllocatedFrames(0), mAllocatedBytes(0) { }
/*! @dtor ~AUBufferList */
~AUBufferList();
/*! @method PrepareBuffer */
AudioBufferList & PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames);
/*! @method PrepareNullBuffer */
AudioBufferList & PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames);
/*! @method SetBufferList */
AudioBufferList & SetBufferList(const AudioBufferList &abl) {
if (mAllocatedStreams < abl.mNumberBuffers)
COMPONENT_THROW(-1);
mPtrState = kPtrsToExternalMemory;
memcpy(mPtrs, &abl, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl);
return *mPtrs;
}
/*! @method SetBuffer */
void SetBuffer(UInt32 index, const AudioBuffer &ab) {
if (mPtrState == kPtrsInvalid || index >= mPtrs->mNumberBuffers)
COMPONENT_THROW(-1);
mPtrState = kPtrsToExternalMemory;
mPtrs->mBuffers[index] = ab;
}
/*! @method InvalidateBufferList */
void InvalidateBufferList() { mPtrState = kPtrsInvalid; }
/*! @method GetBufferList */
AudioBufferList & GetBufferList() const {
if (mPtrState == kPtrsInvalid)
COMPONENT_THROW(-1);
return *mPtrs;
}
/*! @method CopyBufferListTo */
void CopyBufferListTo(AudioBufferList &abl) const {
if (mPtrState == kPtrsInvalid)
COMPONENT_THROW(-1);
memcpy(&abl, mPtrs, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl);
}
/*! @method CopyBufferContentsTo */
void CopyBufferContentsTo(AudioBufferList &abl) const {
if (mPtrState == kPtrsInvalid)
COMPONENT_THROW(-1);
const AudioBuffer *srcbuf = mPtrs->mBuffers;
AudioBuffer *destbuf = abl.mBuffers;
for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) {
if (i >= mPtrs->mNumberBuffers) // duplicate last source to additional outputs [4341137]
--srcbuf;
if (destbuf->mData != srcbuf->mData)
memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
destbuf->mDataByteSize = srcbuf->mDataByteSize;
}
}
/*! @method Allocate */
void Allocate(const CAStreamBasicDescription &format, UInt32 nFrames);
/*! @method Deallocate */
void Deallocate();
/*! @method UseExternalBuffer */
void UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf);
// AudioBufferList utilities
/*! @method ZeroBuffer */
static void ZeroBuffer(AudioBufferList &abl) {
AudioBuffer *buf = abl.mBuffers;
for (UInt32 i = abl.mNumberBuffers ; i--; ++buf)
memset(buf->mData, 0, buf->mDataByteSize);
}
#if DEBUG
/*! @method PrintBuffer */
static void PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames = 8, bool asFloats = true);
#endif
/*! @method GetAllocatedFrames */
UInt32 GetAllocatedFrames() const { return mAllocatedFrames; }
private:
/*! @ctor AUBufferList */
AUBufferList(AUBufferList &) { } // prohibit copy constructor
/*! @var mPtrState */
EPtrState mPtrState;
/*! @var mExternalMemory */
bool mExternalMemory;
/*! @var mPtrs */
AudioBufferList * mPtrs;
/*! @var mMemory */
Byte * mMemory;
/*! @var mAllocatedStreams */
UInt32 mAllocatedStreams;
/*! @var mAllocatedFrames */
UInt32 mAllocatedFrames;
/*! @var mAllocatedBytes */
UInt32 mAllocatedBytes;
};
// Allocates an array of samples (type T), to be optimally aligned for the processor
/*! @class TAUBuffer */
template <class T>
class TAUBuffer {
public:
enum {
kAlignInterval = 0x10,
kAlignMask = kAlignInterval - 1
};
/*! @ctor TAUBuffer.0 */
TAUBuffer() : mMemObject(NULL), mAlignedBuffer(NULL), mBufferSizeBytes(0)
{
}
/*! @ctor TAUBuffer.1 */
TAUBuffer(UInt32 numElems, UInt32 numChannels) : mMemObject(NULL), mAlignedBuffer(NULL),
mBufferSizeBytes(0)
{
Allocate(numElems, numChannels);
}
/*! @dtor ~TAUBuffer */
~TAUBuffer()
{
Deallocate();
}
/*! @method Allocate */
void Allocate(UInt32 numElems) // can also re-allocate
{
UInt32 reqSize = numElems * sizeof(T);
if (mMemObject != NULL && reqSize == mBufferSizeBytes)
return; // already allocated
mBufferSizeBytes = reqSize;
mMemObject = CA_realloc(mMemObject, reqSize);
UInt32 misalign = (uintptr_t)mMemObject & kAlignMask;
if (misalign) {
mMemObject = CA_realloc(mMemObject, reqSize + kAlignMask);
mAlignedBuffer = (T *)((char *)mMemObject + kAlignInterval - misalign);
} else
mAlignedBuffer = (T *)mMemObject;
}
/*! @method Deallocate */
void Deallocate()
{
if (mMemObject == NULL) return; // so this method has no effect if we're using
// an external buffer
free(mMemObject);
mMemObject = NULL;
mAlignedBuffer = NULL;
mBufferSizeBytes = 0;
}
/*! @method AllocateClear */
void AllocateClear(UInt32 numElems) // can also re-allocate
{
Allocate(numElems);
Clear();
}
/*! @method Clear */
void Clear()
{
memset(mAlignedBuffer, 0, mBufferSizeBytes);
}
// accessors
/*! @method operator T *()@ */
operator T *() { return mAlignedBuffer; }
private:
/*! @var mMemObject */
void * mMemObject; // null when using an external buffer
/*! @var mAlignedBuffer */
T * mAlignedBuffer; // always valid once allocated
/*! @var mBufferSizeBytes */
UInt32 mBufferSizeBytes;
};
#endif // __AUBuffer_h__

View File

@@ -0,0 +1,155 @@
/*
File: AUInputFormatConverter.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUInputFormatConverter_h__
#define __AUInputFormatConverter_h__
#include "FormatConverterClient.h"
#include "AUTimestampGenerator.h"
// ____________________________________________________________________________
// AUInputFormatConverter
//
// Subclass of FormatConverterClient that applies a format conversion
// to an input of an AudioUnit.
/*! @class AUInputFormatConverter */
class AUInputFormatConverter : public FormatConverterClient {
public:
/*! @ctor AUInputFormatConverter */
AUInputFormatConverter(AUBase *hostAU, int inputBus) :
mHost(hostAU),
mHostBus(inputBus),
mPreviousSilentFrames(0x1000)
{
#if DEBUG
mTimestampGenerator.mVerbosity = 0;
strcpy(mTimestampGenerator.mDebugName, "AUConverter");
#endif
}
// need to subsequently call Initialize, with the desired formats
/*! @dtor ~AUInputFormatConverter */
~AUInputFormatConverter()
{
}
virtual OSStatus Initialize(const AudioStreamBasicDescription &src, const AudioStreamBasicDescription &dest)
{
OSStatus err = FormatConverterClient::Initialize(src, dest);
if (err) return err;
mIsPCMToPCM = (src.mFormatID == kAudioFormatLinearPCM) && (dest.mFormatID == kAudioFormatLinearPCM);
mHasSRC = (fnonzero(src.mSampleRate) && fnonzero(dest.mSampleRate) && fnotequal(src.mSampleRate, dest.mSampleRate));
return ca_noErr;
}
virtual OSStatus Reset()
{
mPreviousSilentFrames = 0x1000;
mTimestampGenerator.Reset();
return FormatConverterClient::Reset();
}
void SetStartInputTimeAtZero(bool b)
{
mTimestampGenerator.SetStartInputAtZero(b);
}
/*! @method FillComplexBuffer */
OSStatus AUFillComplexBuffer(const AudioTimeStamp & inTimeStamp,
UInt32 & ioOutputDataPacketSize,
AudioBufferList & outOutputData,
AudioStreamPacketDescription* outPacketDescription,
bool& outSilence)
{
mTimestampGenerator.AddOutputTime(inTimeStamp, ioOutputDataPacketSize, mOutputFormat.mSampleRate);
mSilentOutput = true;
OSStatus err = FillComplexBuffer(ioOutputDataPacketSize, outOutputData, outPacketDescription);
if (mSilentOutput) {
if (!mIsPCMToPCM || (mHasSRC && mPreviousSilentFrames < 32))
mSilentOutput = false;
mPreviousSilentFrames += ioOutputDataPacketSize;
} else
mPreviousSilentFrames = 0;
outSilence = mSilentOutput;
return err;
}
/*! @method FormatConverterInputProc */
virtual OSStatus FormatConverterInputProc(
UInt32 & ioNumberDataPackets,
AudioBufferList & ioData,
AudioStreamPacketDescription** outDataPacketDescription)
{
OSStatus err = ca_noErr;
AudioUnitRenderActionFlags actionFlags = 0;
AUInputElement *input = mHost->GetInput(mHostBus);
*ioNumberDataPackets = std::min(*ioNumberDataPackets, This->mHost->GetMaxFramesPerSlice());
const AudioTimeStamp &inputTime = mTimestampGenerator.GenerateInputTime(ioNumberDataPackets, mInputFormat.mSampleRate);
err = input->PullInput(actionFlags, inputTime, mHostBus, ioNumberDataPackets);
if (!err) {
input->CopyBufferListTo(ioData);
if (!(actionFlags & kAudioUnitRenderAction_OutputIsSilence))
mSilentOutput = false;
}
return err;
}
protected:
/*! @var mHost */
AUBase * mHost;
/*! @var mHostBus */
int mHostBus;
AUTimestampGenerator mTimestampGenerator;
bool mIsPCMToPCM;
bool mHasSRC;
bool mSilentOutput;
UInt32 mPreviousSilentFrames;
};
#endif // __AUInputFormatConverter_h__

View File

@@ -0,0 +1,138 @@
/*
File: AUMIDIDefs.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUMIDIDefs_h__
#define __AUMIDIDefs_h__
#if !defined(__TMidiMessage) /* DAS HACK */
enum
{
kMidiMessage_NoteOff = 0x80,
kMidiMessage_NoteOn = 0x90,
kMidiMessage_PolyPressure = 0xA0,
kMidiMessage_ControlChange = 0xB0,
kMidiMessage_ProgramChange = 0xC0,
kMidiMessage_ChannelPressure = 0xD0,
kMidiMessage_PitchWheel = 0xE0,
kMidiMessage_SysEx = 0xF0,
kMidiMessage_SysEx_End = 0xF7,
kMidiMessage_MetaEvent = 0xFF
};
#endif
enum
{
kMidiController_BankSelect = 0,
kMidiController_ModWheel = 1,
kMidiController_Breath = 2,
kMidiController_Foot = 4,
kMidiController_PortamentoTime = 5,
kMidiController_DataEntry = 6,
kMidiController_Volume = 7,
kMidiController_Balance = 8,
kMidiController_Pan = 10,
kMidiController_Expression = 11,
// these controls have a (0-63) == off, (64-127) == on
kMidiController_Sustain = 64, //hold1
kMidiController_Portamento = 65,
kMidiController_Sostenuto = 66,
kMidiController_Soft = 67,
kMidiController_LegatoPedal = 68,
kMidiController_Hold2Pedal = 69,
kMidiController_FilterResonance = 71,
kMidiController_ReleaseTime = 72,
kMidiController_AttackTime = 73,
kMidiController_Brightness = 74,
kMidiController_DecayTime = 75,
kMidiController_VibratoRate = 76,
kMidiController_VibratoDepth = 77,
kMidiController_VibratoDelay = 78,
// these controls have a 0-127 range and in MIDI they have no LSB (so fractional values are lost in MIDI)
kMidiController_ReverbLevel = 91,
kMidiController_ChorusLevel = 93,
kMidiController_RPN_LSB = 100,
kMidiController_RPN_MSB = 101,
kMidiController_AllSoundOff = 120,
kMidiController_ResetAllControllers = 121,
kMidiController_AllNotesOff = 123,
kMidiController_OmniModeOff = 124,
kMidiController_OmniModeOn = 125,
kMidiController_MonoModeOn = 126,
kMidiController_MonoModeOff = 127
};
// RPN values
enum
{
kMidiControllerValue_RPNPitchBendSensitivity = 0,
kMidiControllerValue_RPNChannelFineTuning = 1,
kMidiControllerValue_RPNChannelCoarseTuning = 2,
kMidiControllerValue_RPNModDepthRange = 5,
kMidiControllerValue_RPNNull = 0x3fff //! 0x7f/0x7f
};
// GM2 Sound Bank Constants
enum
{
kGM2MelodicBank = 0x7900,
kGM2PercussionBank = 0x7800,
kGSPercussionBank = 0x7f00,
kXGSFXBank = 0x7E00,
kXGPercussionBank = kGSPercussionBank,
kBankMSBMask = 0xff00
};
enum
{
kMSBController_MidPoint = 0x40
};
#endif // __AUMIDIDefs_h__

View File

@@ -0,0 +1,93 @@
/*
File: AUSilentTimeout.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUSilentTimeout
#define __AUSilentTimeout
class AUSilentTimeout
{
public:
AUSilentTimeout()
: mTimeoutCounter(0),
mResetTimer(true)
{};
void Process(UInt32 inFramesToProcess, UInt32 inTimeoutLimit, bool &ioSilence )
{
if(ioSilence )
{
if(mResetTimer )
{
mTimeoutCounter = inTimeoutLimit;
mResetTimer = false;
}
if(mTimeoutCounter > 0 )
{
mTimeoutCounter -= inFramesToProcess;
ioSilence = false;
}
}
else
{
// signal to reset the next time we receive silence
mResetTimer = true;
}
}
void Reset()
{
mResetTimer = true;
};
private:
SInt32 mTimeoutCounter;
bool mResetTimer;
};
#endif // __AUSilentTimeout

View File

@@ -0,0 +1,203 @@
/*
File: AUTimestampGenerator.cpp
Abstract: AUTimestampGenerator.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUTimestampGenerator.h"
#include "CAMath.h"
#if DEBUG
static double DebugHostTime(const AudioTimeStamp &ts)
{
static UInt64 baseHostTime = 0;
if (!(ts.mFlags & kAudioTimeStampHostTimeValid))
return -1.;
if (baseHostTime == 0)
baseHostTime = ts.mHostTime;
return double(SInt64(ts.mHostTime) - SInt64(baseHostTime)) * CAHostTimeBase::GetInverseFrequency();
}
#endif
void AUTimestampGenerator::AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj)
{
mState.mRateScalarAdj = rateScalarAdj;
mState.mLastOutputTime = mState.mCurrentOutputTime;
mState.mInputSampleTimeForOutputPull = mState.mNextInputSampleTime;
mState.mCurrentOutputTime = inTimeStamp;
if (mState.mBypassed)
return;
if (mState.mHostTimeDiscontinuityCorrection && !(mState.mCurrentOutputTime.mFlags & kAudioTimeStampHostTimeValid) && (mState.mLastOutputTime.mFlags & kAudioTimeStampHostTimeValid)) {
// no host time here but we had one last time, interpolate one
double rateScalar = (mState.mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) ? mState.mCurrentOutputTime.mRateScalar : 1.0;
Float64 deltaSamples = mState.mCurrentOutputTime.mSampleTime - mState.mLastOutputTime.mSampleTime;
mState.mCurrentOutputTime.mHostTime = mState.mLastOutputTime.mHostTime +
UInt64(CAHostTimeBase::GetFrequency() * deltaSamples * rateScalar / outputSampleRate);
mState.mCurrentOutputTime.mFlags |= kAudioTimeStampHostTimeValid;
#if DEBUG
if (mVerbosity > 1)
printf("synthesized host time: %.3f (%.3f + %.f smp @ %.f Hz, rs %.3f\n", DebugHostTime(mState.mCurrentOutputTime), DebugHostTime(mState.mLastOutputTime), deltaSamples, outputSampleRate, rateScalar);
#endif
}
// copy rate scalar
if (rateScalarAdj != 1.0) {
if (mState.mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid)
mState.mCurrentOutputTime.mRateScalar *= rateScalarAdj;
else {
mState.mCurrentOutputTime.mRateScalar = rateScalarAdj;
mState.mCurrentOutputTime.mFlags |= kAudioTimeStampRateScalarValid;
}
}
if (mFirstTime) {
mFirstTime = false;
mState.mDiscontinuous = false;
mState.mDiscontinuityDeltaSamples = 0.;
if (!mState.mStartInputAtZero) {
mState.mNextInputSampleTime = mState.mCurrentOutputTime.mSampleTime;
mState.mInputSampleTimeForOutputPull = mState.mNextInputSampleTime;
}
} else {
mState.mDiscontinuous = fnotequal(mState.mCurrentOutputTime.mSampleTime, mState.mNextOutputSampleTime);
mState.mDiscontinuityDeltaSamples = mState.mCurrentOutputTime.mSampleTime - mState.mNextOutputSampleTime;
// time should never go backwards...
if (mState.mDiscontinuityDeltaSamples < 0.)
mState.mDiscontinuityDeltaSamples = 0.;
#if DEBUG
if (mVerbosity > 1)
if (mState.mDiscontinuous)
printf("%-20.20s: *** DISCONTINUOUS, got " TSGFMT ", expected " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentOutputTime.mSampleTime, (SInt64)mState.mNextOutputSampleTime);
#endif
}
mState.mNextOutputSampleTime = mState.mCurrentOutputTime.mSampleTime + expectedDeltaFrames;
}
const AudioTimeStamp & AUTimestampGenerator::GenerateInputTime(Float64 framesToAdvance, double inputSampleRate, bool advanceHostTime)
{
if (mState.mBypassed)
return mState.mCurrentOutputTime;
double inputSampleTime;
mState.mCurrentInputTime.mFlags = kAudioTimeStampSampleTimeValid;
double rateScalar = 1.0;
// propagate rate scalar
if (mState.mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) {
mState.mCurrentInputTime.mFlags |= kAudioTimeStampRateScalarValid;
mState.mCurrentInputTime.mRateScalar = rateScalar = mState.mCurrentOutputTime.mRateScalar;
}
// propagate host time and sample time
if (mState.mCurrentOutputTime.mFlags & kAudioTimeStampHostTimeValid) {
mState.mCurrentInputTime.mFlags |= kAudioTimeStampHostTimeValid;
if (advanceHostTime) {
Float64 deltaSamples = mState.mNextInputSampleTime - mState.mInputSampleTimeForOutputPull;
Float64 deltaSeconds = (deltaSamples / inputSampleRate) * mState.mRateScalarAdj;
UInt64 deltaHostTime = (UInt64)(deltaSeconds * CAHostTimeBase::GetFrequency());
mState.mCurrentInputTime.mHostTime = mState.mCurrentOutputTime.mHostTime + deltaHostTime;
} else {
mState.mCurrentInputTime.mHostTime = mState.mCurrentOutputTime.mHostTime;
}
if (mState.mHostTimeDiscontinuityCorrection && mState.mDiscontinuous && (mState.mLastOutputTime.mFlags & kAudioTimeStampHostTimeValid)) {
// we had a discontinuous output time, need to resync by interpolating
// a sample time that is appropriate to the host time
UInt64 deltaHostTime = mState.mCurrentOutputTime.mHostTime - mState.mLastOutputTime.mHostTime;
double deltaSeconds = double(deltaHostTime) * CAHostTimeBase::GetInverseFrequency();
// samples/second * seconds = samples
double deltaSamples = floor(inputSampleRate / rateScalar * deltaSeconds + 0.5);
double lastInputSampleTime = mState.mCurrentInputTime.mSampleTime;
inputSampleTime = lastInputSampleTime + deltaSamples;
#if DEBUG
if (mVerbosity > 1)
printf("%-20.20s: adjusted input time: " TSGFMT " -> " TSGFMT " (SR=%.3f, rs=%.3f)\n", mDebugName, (SInt64)lastInputSampleTime, (SInt64)inputSampleTime, inputSampleRate, rateScalar);
#endif
mState.mDiscontinuous = false;
} else {
inputSampleTime = mState.mNextInputSampleTime;
}
} else {
// we don't know the host time, so we can't do much
inputSampleTime = mState.mNextInputSampleTime;
}
if (!mState.mHostTimeDiscontinuityCorrection && fnonzero(mState.mDiscontinuityDeltaSamples))
{
// we had a discontinuous output time, need to resync by propagating the
// detected discontinuity, taking the rate scalar adjustment into account
inputSampleTime += floor(mState.mDiscontinuityDeltaSamples / mState.mRateScalarAdj + 0.5);
#if DEBUG
if (mVerbosity > 1)
printf("%-20.20s: adjusted input time: %.0f -> %.0f (SR=%.3f, rs=%.3f, delta=%.0f)\n", mDebugName, mState.mNextInputSampleTime, inputSampleTime, inputSampleRate, mState.mRateScalarAdj, mState.mDiscontinuityDeltaSamples);
#endif
mState.mDiscontinuityDeltaSamples = 0.;
}
// propagate word clock
if (mState.mCurrentOutputTime.mFlags & kAudioTimeStampWordClockTimeValid) {
mState.mCurrentInputTime.mFlags |= kAudioTimeStampWordClockTimeValid;
mState.mCurrentInputTime.mWordClockTime = mState.mCurrentOutputTime.mWordClockTime;
}
// propagate SMPTE time
if (mState.mCurrentOutputTime.mFlags & kAudioTimeStampSMPTETimeValid) {
mState.mCurrentInputTime.mFlags |= kAudioTimeStampSMPTETimeValid;
mState.mCurrentInputTime.mSMPTETime = mState.mCurrentOutputTime.mSMPTETime;
}
// store the input sample time and expected next input time
mState.mCurrentInputTime.mSampleTime = inputSampleTime;
mState.mNextInputSampleTime = inputSampleTime + framesToAdvance;
#if DEBUG
if (mVerbosity > 0) {
printf("%-20.20s: out = " TSGFMT " (%10.3fs) in = " TSGFMT " (%10.3fs) delta = " TSGFMT " advance = " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentOutputTime.mSampleTime, DebugHostTime(mState.mCurrentOutputTime), (SInt64)inputSampleTime, DebugHostTime(mState.mCurrentInputTime), (SInt64)(mState.mCurrentOutputTime.mSampleTime - inputSampleTime), (SInt64)framesToAdvance);
}
#endif
return mState.mCurrentInputTime;
}

View File

@@ -0,0 +1,163 @@
/*
File: AUTimestampGenerator.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUTimestampGenerator_h__
#define __AUTimestampGenerator_h__
#include <math.h>
#include "CAHostTimeBase.h"
#include <stdio.h>
#define TSGFMT "0x%10qx"
//#define TSGFMT "%10qd"
// This class generates a continuously increasing series of timestamps based
// on a series of potentially discontinuous timestamps (as can be delivered from
// CoreAudio in the event of an overload or major engine change).
// N.B.: "output" = downstream (source) timestamp
// "input" = upstream (derived) timestamp
class AUTimestampGenerator {
public:
AUTimestampGenerator(bool hostTimeDiscontinuityCorrection = false)
{
mState.mStartInputAtZero = true;
mState.mBypassed = false;
mState.mHostTimeDiscontinuityCorrection = hostTimeDiscontinuityCorrection;
#if DEBUG
mVerbosity = 0;
snprintf(mDebugName, sizeof(mDebugName), "tsg @ %p", this);
#endif
// CAHostTimeBase should be used instead of the calls in <CoreAudio/HostTime.h>
// we make this call here to ensure that this is initialized, otherwise the first time
// you do actually call CAHostTimeBase to do work, can be on the render thread, and lead to unwanted VM faults
CAHostTimeBase::GetFrequency();
Reset();
}
void SetStartInputAtZero(bool b) { mState.mStartInputAtZero = b; }
bool GetStartInputAtZero() const { return mState.mStartInputAtZero; }
// bypassing is intended for a narrow special case. the upstream sample time will always be the same as the downstream time.
void SetBypassed(bool b) { mState.mBypassed = b; }
bool GetBypassed() const { return mState.mBypassed; }
// Call this to reset the timeline.
void Reset()
{
mState.mCurrentInputTime.mSampleTime = 0.;
mState.mNextInputSampleTime = 0.;
mState.mCurrentOutputTime.mSampleTime = 0.;
mState.mNextOutputSampleTime = 0.;
mState.mLastOutputTime.mFlags = 0;
mState.mRateScalarAdj = 1.;
mFirstTime = true;
#if DEBUG
if (mVerbosity)
printf("%-20.20s: Reset\n", mDebugName);
#endif
}
// Call this once per render cycle with the downstream timestamp.
// expectedDeltaFrames is the expected difference between the current and NEXT
// downstream timestamps.
// sampleRate is the OUTPUT sample rate.
void AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj=1.0);
// Call this once per render cycle to obtain the upstream timestamp.
// framesToAdvance is the number of frames the input timeline is to be
// advanced during this render cycle.
// sampleRate is the INPUT sample rate.
const AudioTimeStamp & GenerateInputTime(Float64 framesToAdvance, double inputSampleRate, bool advanceHostTime = false);
// this can be called to override the setting of the next input sample time in GenerateInputTime
void Advance(Float64 framesToAdvance)
{
#if DEBUG
if (mVerbosity > 1)
printf("%-20.20s: ADVANCE in = " TSGFMT " advance = " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentInputTime.mSampleTime, (SInt64)framesToAdvance);
#endif
mState.mNextInputSampleTime = mState.mCurrentInputTime.mSampleTime + framesToAdvance;
}
struct State {
AudioTimeStamp mCurrentInputTime;
Float64 mNextInputSampleTime;
Float64 mNextOutputSampleTime;
Float64 mInputSampleTimeForOutputPull;
AudioTimeStamp mLastOutputTime;
AudioTimeStamp mCurrentOutputTime;
bool mStartInputAtZero; // if true, input timeline starts at 0, else it starts
// synced with the output timeline
bool mDiscontinuous;
bool mBypassed;
Float64 mDiscontinuityDeltaSamples;
double mRateScalarAdj;
bool mHostTimeDiscontinuityCorrection; // If true, propagate timestamp discontinuities using host time.
};
void GetState(State& outState) const { outState = mState; }
void SetState(State const& inState) { mState = inState; mFirstTime = false; }
private:
struct State mState;
bool mFirstTime;
#if DEBUG
public:
int mVerbosity;
char mDebugName[64];
#endif
};
#endif // __AUTimestampGenerator_h__

View File

@@ -0,0 +1,169 @@
/*
File: AUOutputBL.cpp
Abstract: AUOutputBL.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUOutputBL.h"
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioUnit/AUComponent.h>
#else
#include <AUComponent.h>
#endif
/*
struct AudioBufferList
{
UInt32 mNumberBuffers;
AudioBuffer mBuffers[1];
};
struct AudioBuffer
{
UInt32 mNumberChannels; // number of interleaved channels in the buffer
UInt32 mDataByteSize; // the size of the buffer pointed to by mData
void* mData; // the pointer to the buffer
};
*/
AUOutputBL::AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames)
: mFormat (inDesc),
mBufferMemory(NULL),
mBufferList (NULL),
mNumberBuffers (0), // keep this here, so can ensure integrity of ABL
mBufferSize (0),
mFrames(inDefaultNumFrames)
{
mNumberBuffers = mFormat.IsInterleaved() ? 1 : mFormat.NumberChannels();
mBufferList = reinterpret_cast<AudioBufferList*>(new Byte[offsetof(AudioBufferList, mBuffers) + (mNumberBuffers * sizeof(AudioBuffer))]);
}
AUOutputBL::~AUOutputBL()
{
if (mBufferMemory)
delete[] mBufferMemory;
if (mBufferList)
delete [] (Byte *)mBufferList;
}
void AUOutputBL::Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated)
{
UInt32 channelsPerBuffer = mFormat.IsInterleaved() ? mFormat.NumberChannels() : 1;
if (mBufferMemory == NULL || inWantNullBufferIfAllocated)
{
mBufferList->mNumberBuffers = mNumberBuffers;
AudioBuffer *buf = &mBufferList->mBuffers[0];
for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) {
buf->mNumberChannels = channelsPerBuffer;
buf->mDataByteSize = mFormat.FramesToBytes (inNumFrames);
buf->mData = NULL;
}
}
else
{
UInt32 nBytes = mFormat.FramesToBytes (inNumFrames);
if ((nBytes * mNumberBuffers) > AllocatedBytes())
throw OSStatus(kAudioUnitErr_TooManyFramesToProcess);
mBufferList->mNumberBuffers = mNumberBuffers;
AudioBuffer *buf = &mBufferList->mBuffers[0];
Byte* p = mBufferMemory;
for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) {
buf->mNumberChannels = channelsPerBuffer;
buf->mDataByteSize = nBytes;
buf->mData = p;
p += mBufferSize;
}
}
}
void AUOutputBL::Allocate (UInt32 inNumFrames)
{
if (inNumFrames)
{
UInt32 nBytes = mFormat.FramesToBytes (inNumFrames);
if (nBytes <= AllocatedBytes())
return;
// align successive buffers for Altivec and to take alternating
// cache line hits by spacing them by odd multiples of 16
if (mNumberBuffers > 1)
nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10;
mBufferSize = nBytes;
UInt32 memorySize = mBufferSize * mNumberBuffers;
Byte *newMemory = new Byte[memorySize];
memset(newMemory, 0, memorySize); // make buffer "hot"
Byte *oldMemory = mBufferMemory;
mBufferMemory = newMemory;
delete[] oldMemory;
mFrames = inNumFrames;
}
else
{
if (mBufferMemory) {
delete [] mBufferMemory;
mBufferMemory = NULL;
}
mBufferSize = 0;
mFrames = 0;
}
}
#if DEBUG
void AUOutputBL::Print()
{
printf ("AUOutputBL::Print\n");
mFormat.Print();
printf ("Num Buffers:%d, mFrames:%d, allocatedMemory:%c\n", (int)mBufferList->mNumberBuffers, (int)mFrames, (mBufferMemory != NULL ? 'T' : 'F'));
AudioBuffer *buf = &mBufferList->mBuffers[0];
for (UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i, ++buf)
printf ("\tBuffer:%d, Size:%d, Chans:%d, Buffer:%p\n", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData);
}
#endif

View File

@@ -0,0 +1,118 @@
/*
File: AUOutputBL.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __AUOutputBL_h__
#define __AUOutputBL_h__
#include "CAStreamBasicDescription.h"
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#else
#endif
// ____________________________________________________________________________
//
// AUOutputBL - Simple Buffer List wrapper targetted to use with retrieving AU output
// Works in one of two ways (both adjustable)... Can use it with NULL pointers, or allocate
// memory to receive the data in.
// Before using this with any call to AudioUnitRender, it needs to be Prepared
// as some calls to AudioUnitRender can reset the ABL
class AUOutputBL {
public:
// you CANNOT use one of these - it will crash!
// AUOutputBL ();
// this is the constructor that you use
// it can't be reset once you've constructed it
AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames = 512);
~AUOutputBL();
void Prepare ()
{
Prepare (mFrames);
}
// this version can throw if this is an allocted ABL and inNumFrames is > AllocatedFrames()
// you can set the bool to true if you want a NULL buffer list even if allocated
// inNumFrames must be a valid number (will throw if inNumFrames is 0)
void Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated = false);
AudioBufferList* ABL() { return mBufferList; }
// You only need to call this if you want to allocate a buffer list
// if you want an empty buffer list, just call Prepare()
// if you want to dispose previously allocted memory, pass in 0
// then you either have an empty buffer list, or you can re-allocate
// Memory is kept around if an Allocation request is less than what is currently allocated
void Allocate (UInt32 inNumberFrames);
UInt32 AllocatedFrames() const { return mFrames; }
const CAStreamBasicDescription& GetFormat() const { return mFormat; }
#if DEBUG
void Print();
#endif
private:
UInt32 AllocatedBytes () const { return (mBufferSize * mNumberBuffers); }
CAStreamBasicDescription mFormat;
Byte* mBufferMemory;
AudioBufferList* mBufferList;
UInt32 mNumberBuffers;
UInt32 mBufferSize;
UInt32 mFrames;
// don't want to copy these.. can if you want, but more code to write!
AUOutputBL () {}
AUOutputBL (const AUOutputBL &c);
AUOutputBL& operator= (const AUOutputBL& c);
};
#endif // __AUOutputBL_h__

View File

@@ -0,0 +1,139 @@
/*
File: AUParamInfo.cpp
Abstract: AUParamInfo.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "AUParamInfo.h"
#include "CAXException.h"
AUParamInfo::AUParamInfo (AudioUnit inAU,
bool inIncludeExpert,
bool inIncludeReadOnly,
AudioUnitScope inScope,
AudioUnitElement inElement)
: mAU (inAU),
mNumParams (0),
mParamListID(NULL),
mScope (inScope),
mElement (inElement)
{
UInt32 size;
OSStatus result = AudioUnitGetPropertyInfo(mAU, kAudioUnitProperty_ParameterList, inScope, mElement, &size, NULL);
if (size == 0 || result) return;
int nparams = size / sizeof(AudioUnitPropertyID);
mParamListID = new AudioUnitParameterID[nparams];
memset (mParamListID, 0xFF, size);
AudioUnitParameterID *paramList = new AudioUnitParameterID[nparams];
result = AudioUnitGetProperty(mAU, kAudioUnitProperty_ParameterList, mScope, mElement, paramList, &size);
if (result) {
delete [] mParamListID;
delete [] paramList;
mParamListID = NULL;
return;
}
ParameterMap params;
for (int i = 0; i < nparams; ++i)
{
CAAUParameter auvp (mAU, paramList[i], mScope, mElement); // took out only using global scope in CAAUParameter creation
const AudioUnitParameterInfo &paramInfo = auvp.ParamInfo();
// don't include if parameter can't be read or written
if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable)
&& !(paramInfo.flags & kAudioUnitParameterFlag_IsReadable))
continue;
// only include if expert params wanted
if (!inIncludeExpert && auvp.IsExpert())
continue;
// only include if read only params are wanted
if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable)
&& (paramInfo.flags & kAudioUnitParameterFlag_IsReadable))
{
if (!inIncludeReadOnly)
continue;
}
mParamListID[mNumParams] = paramList[i];
mNumParams++;
// ok - if we're here, then we have a parameter we are going to display.
UInt32 clump = 0;
auvp.GetClumpID (clump);
mParams[clump].push_back (auvp);
}
delete [] paramList;
}
AUParamInfo::~AUParamInfo()
{
delete [] mParamListID;
}
UInt32 AUParamInfo::NumParamsForClump (UInt32 inClump) const
{
ParameterMap::const_iterator it = mParams.find(inClump);
if (it != mParams.end())
return static_cast<UInt32>((*it).second.size());
return 0;
}
const CAAUParameter* AUParamInfo::GetParamInfo (AudioUnitParameterID inParamID) const
{
for (ParameterMap::const_iterator it = mParams.begin(); it != mParams.end(); ++it) {
const ParameterList &list = (*it).second;
for (ParameterList::const_iterator iter = list.begin(); iter != list.end(); ++iter) {
if (inParamID == (*iter).mParameterID) {
return &(*iter);
}
}
}
return NULL;
}

View File

@@ -0,0 +1,112 @@
/*
File: AUParamInfo.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include <map>
#include <vector>
#include <AudioUnit/AudioUnit.h>
#include "CAAUParameter.h"
/*
The ParameterMap returned by the Map() method is a map where
- the key is the clumpID
- the value is a ParameterList (vector<CAAUParameter>)
If you have parameters on multiple scopes (or elements within a scope), then you should create one of these
for each scope-element pair
*/
class AUParamInfo {
public:
typedef std::vector <CAAUParameter> ParameterList;
typedef std::map <UInt32, ParameterList, std::less<UInt32> > ParameterMap;
AUParamInfo (AudioUnit inAU,
bool inIncludeExpert,
bool inIncludeReadOnly,
AudioUnitScope inScope = kAudioUnitScope_Global,
AudioUnitElement inElement = 0);
~AUParamInfo();
const ParameterMap& Map () const { return mParams; }
// some convenience methods
UInt32 NumParams () const { return mNumParams; }
AudioUnitParameterID ParamID (UInt32 inIndex) const
{
if (inIndex < mNumParams) return mParamListID[inIndex];
return 0xFFFFFFFF;
}
UInt32 NumClumps () const { return static_cast<UInt32>(mParams.size()); }
UInt32 NumParamsForClump (UInt32 inClump) const;
// returns NULL if there's no info for the parameter
const CAAUParameter* GetParamInfo (AudioUnitParameterID inParamID) const;
AudioUnitScope GetScope () const { return mScope; }
AudioUnitElement GetElement () const { return mElement; }
private:
AudioUnit mAU;
UInt32 mNumParams;
AudioUnitParameterID * mParamListID;
ParameterMap mParams;
AudioUnitScope mScope;
AudioUnitElement mElement;
// disallow
AUParamInfo () {}
AUParamInfo (const AUParamInfo &c) {}
AUParamInfo& operator= (const AUParamInfo& c) { return *this; }
};

View File

@@ -0,0 +1,227 @@
/*
File: CAAUMIDIMap.cpp
Abstract: CAAUMIDIMap.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CAAUMIDIMap.h"
#include <pthread.h>
struct AllMidiTransformers
{
MIDILinearTransformer linearTrans;
MIDILogTransformer logTrans;
MIDIExpTransformer expTrans;
MIDISqrtTransformer sqrtTrans;
MIDISquareTransformer squareTrans;
MIDICubeRtTransformer cubeRtTrans;
MIDICubeTransformer cubeTrans;
};
AllMidiTransformers* gAllMidiTransformers = NULL;
#if TARGET_OS_MAC
static pthread_once_t sOnce = PTHREAD_ONCE_INIT;
static void InitAllMidiTransformers()
{
gAllMidiTransformers = new AllMidiTransformers();
}
static void CheckInitAllMidiTransformers()
{
pthread_once(&sOnce, InitAllMidiTransformers);
}
#endif
MIDIValueTransformer * CAAUMIDIMap::GetTransformer (UInt32 inFlags)
{
#if TARGET_OS_MAC
if (gAllMidiTransformers == NULL)
CheckInitAllMidiTransformers();
#else
if (gAllMidiTransformers == NULL)
gAllMidiTransformers = new AllMidiTransformers();
#endif
if (AudioUnitDisplayTypeIsLogarithmic(inFlags))
return &gAllMidiTransformers->logTrans;
else if (AudioUnitDisplayTypeIsExponential(inFlags))
return &gAllMidiTransformers->expTrans;
else if (AudioUnitDisplayTypeIsSquareRoot(inFlags))
return &gAllMidiTransformers->sqrtTrans;
else if (AudioUnitDisplayTypeIsSquared(inFlags))
return &gAllMidiTransformers->squareTrans;
else if (AudioUnitDisplayTypeIsCubed(inFlags))
return &gAllMidiTransformers->cubeTrans;
else if (AudioUnitDisplayTypeIsCubeRoot(inFlags))
return &gAllMidiTransformers->cubeRtTrans;
else
return &gAllMidiTransformers->linearTrans;
}
// The CALLER of this method must ensure that the status byte's MIDI Command matches!!!
bool CAAUMIDIMap::MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const
{
// see if the channels match first
SInt8 chan = Channel();
// channel matches (if chan is less than zero, "Any Channel" flag is set)
if (chan >= 0 && chan != inChannel)
return false;
// match the special cases first
if (IsKeyEvent()) {
// we're using this key event as an on/off type switch
if (IsBipolar()) {
if (IsKeyPressure()){
if (IsBipolar_OnValue()) {
if (inData2 > 63) {
outLinear = 1;
return true;
}
} else {
if (inData2 < 64) {
outLinear = 0;
return true;
}
}
return false;
}
else {
if (IsBipolar_OnValue()) {
if (inData1 > 63) {
outLinear = 1;
return true;
}
} else {
if (inData1 < 64) {
outLinear = 0;
return true;
}
}
return false;
}
}
if (IsAnyNote()) {
// not quite sure how to interpret this...
if (IsKeyPressure())
outLinear = inData2 / 127.0;
else
outLinear = inData1 / 127.0;
return true;
}
if (mData1 == inData1) {
if (IsKeyPressure())
outLinear = inData2 / 127.0;
else
outLinear = 1;
return true;
}
return false;
}
else if (IsControlChange()) {
// controller ID matches
if (mData1 == inData1) {
if (IsBipolar()) {
if (IsBipolar_OnValue()) {
if (inData2 > 63) {
outLinear = 1;
return true;
}
} else {
if (inData2 < 64) {
outLinear = 0;
return true;
}
}
return false;
}
//printf("this in midi matches %X with ", this);
outLinear = inData2 / 127.;
return true;
}
return false;
}
// this just matches on the patch change value itself...
if (IsPatchChange()) {
if (mData1 == inData1) {
outLinear = 1;
return true;
}
return false;
}
// finally, for the other two, just check the bi-polar matching conditions
// pitch bend and after touch
if (IsBipolar()) {
if (IsBipolar_OnValue()) {
if (inData1 > 63) {
outLinear = 1;
return true;
}
} else {
if (inData1 < 64) {
outLinear = 0;
return true;
}
}
return false;
}
if (IsPitchBend()) {
UInt16 value = (inData2 << 7) | inData1;
outLinear = value / 16383.;
}
else if (IsChannelPressure()) {
outLinear = inData1 / 127.0;
}
return true;
}
void CAAUMIDIMap::Print () const
{
printf ("CAAUMIDIMap:%p, (%u/%u), mParamID %d, IsValid:%c, Status:0x%X, mData1 %d, Flags:0x%X\n", this, (unsigned int)mScope, (unsigned int)mElement, (int)mParameterID, (IsValid() ? 'T' : 'F'), mStatus, mData1, (int)mFlags);
}

View File

@@ -0,0 +1,541 @@
/*
File: CAAUMIDIMap.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __CAAUMIDIMap_h_
#define __CAAUMIDIMap_h_
#include <AudioUnit/AudioUnitProperties.h>
#include <algorithm>
/*
enum {
kAUParameterMIDIMapping_AnyChannelFlag = (1L << 0),
// If this flag is set and mStatus is a MIDI channel message, then the MIDI channel number
// in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.
kAUParameterMIDIMapping_AnyNoteFlag = (1L << 1),
// If this flag is set and mStatus is a Note On, Note Off, or Polyphonic Pressure message,
// the message's note number is ignored; the mapping is from ANY note number.
kAUParameterMIDIMapping_SubRange = (1L << 2),
// set this flag if the midi control should map only to a sub-range of the parameter's value
// then specify that range in the mSubRangeMin and mSubRangeMax members
kAUParameterMIDIMapping_Toggle = (1L << 3),
// this is only useful for boolean typed parameters. When set, it means that the parameter's
// value should be toggled (if true, become false and vice versa) when the represented MIDI message
// is received
kAUParameterMIDIMapping_Bipolar = (1L << 4),
// this can be set to when mapping a MIDI Controller to indicate that the parameter (typically a boolean
// style parameter) will only have its value changed to either the on or off state of a MIDI controller message
// (0 < 64 is off, 64 < 127 is on) such as the sustain pedal. The seeting of the next flag
// (kAUParameterMIDIMapping_Bipolar_On) determine whether the parameter is mapped to the on or off
// state of the controller
kAUParameterMIDIMapping_Bipolar_On = (1L << 5)
// only a valid flag if kAUParameterMIDIMapping_Bipolar is set
};
// The reserved fields here are being used to reserve space (as well as align to 64 bit size) for future use
// When/If these fields are used, the names of the fields will be changed to reflect their functionality
// so, apps should NOT refer to these reserved fields directly by name
typedef struct AUParameterMIDIMapping
{
AudioUnitScope mScope;
AudioUnitElement mElement;
AudioUnitParameterID mParameterID;
UInt32 mFlags;
Float32 mSubRangeMin;
Float32 mSubRangeMax;
UInt8 mStatus;
UInt8 mData1;
UInt8 reserved1; // MUST be set to zero
UInt8 reserved2; // MUST be set to zero
UInt32 reserved3; // MUST be set to zero
} AUParameterMIDIMapping;
*/
/*
Parameter To MIDI Mapping Properties
These properties are used to:
Describe a current set of mappings between MIDI messages and Parameter value setting
Create a mapping between a parameter and a MIDI message through either:
- explicitly adding (or removing) the mapping
- telling the AU to hot-map the next MIDI message to a specified Parameter
The same MIDI Message can map to one or more parameters
One Parameter can be mapped from multiple MIDI messages
In general usage, these properties only apply to AU's that implement the MIDI API
AU Instruments (type=='aumu') and Music Effects (type == 'aumf')
These properties are used in the Global scope. The scope and element members of the structure describe
the scope and element of the parameter. In all usages, mScope, mElement and mParameterID must be
correctly specified.
* The AUParameterMIDIMapping Structure
Command mStatus mData1
Note Off 0x8n Note Num
Note On 0x9n Note Num
Key Pressure 0xAn Note Num
Control Change 0xBn ControllerID
Patch Change 0xCn Patch Num
Channel Pressure DxDn 0 (Unused)
Pitch Bend 0xEn 0 (Unused)
(where n is 0-0xF to correspond to MIDI channels 1-16)
Details:
In general MIDI Commands can be mapped to either a specific channel as specified in the mStatus bit.
If the kAUParameterMIDIMapping_AnyChannelFlag bit is set mStatus is a MIDI channel message, then the
MIDI channel number in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.
For note commands (note on, note off, key pressure), the MIDI message can trigger either with just a specific
note number, or any note number if the kAUParameterMIDIMapping_AnyNoteFlag bit is set. In these instances, the
note number is used as the trigger value (for instance, a note message could be used to set the
cut off frequency of a filter).
The Properties:
kAudioUnitProperty_AllParameterMIDIMappings array of AUParameterMIDIMapping (read/write)
This property is used to both retreive and set the current mapping state between (some/many/all of) its parameters
and MIDI messages. When set, it should replace any previous mapped settings the AU had.
If this property is implemented by a non-MIDI capable AU (such as an 'aufx' type), then the property is
read only, and recommends a suggested set of mappings for the host to perform. In this case, it is the
host's responsibility to map MIDI message to the AU parameters. As described previously, there are a set
of default mappings (see AudioToolbox/AUMIDIController.h) that the host can recommend to the user
in this circumstance.
This property's size will be very dynamic, depending on the number of mappings currently in affect, so the
caller should always get the size of the property first before retrieving it. The AU should return an error
if the caller doesn't provide enough space to return all of the current mappings.
kAudioUnitProperty_AddParameterMIDIMapping array of AUParameterMIDIMapping (write only)
This property is used to Add mappings to the existing set of mappings the AU possesses. It does NOT replace
any existing mappings.
kAudioUnitProperty_RemoveParameterMIDIMapping array of AUParameterMIDIMapping (write only)
This property is used to remove the specified mappings from the AU. If a mapping is specified that does not
currently exist in the AU, then it should just be ignored.
kAudioUnitProperty_HotMapParameterMIDIMapping AUParameterMIDIMapping (read/write)
This property is used in two ways, determined by the value supplied by the caller.
(1) If a mapping struct is provided, then that struct provides *all* of the information that the AU should
use to map the parameter, *except* for the MIDI message. The AU should then listen for the next MIDI message
and associate that MIDI message with the supplied AUParameter mapping. When this MIDI message is received and
the mapping made, the AU should also issue a notification on this property
(kAudioUnitProperty_HotMapParameterMIDIMapping) to indicate to the host that the mapping has been made. The host
can then retrieve the mapping that was made by getting the value of this property.
To avoid possible confusion, it is recommended that once the host has retrieved this mapping (if it is
presenting a UI to describe the mappings for example), that it then clears the mapping state as described next.
Thus, the only time this property will return a valid value is when the AU has made a mapping. If the AU's mapping
state has been cleared (or it has not been asked to make a mapping), then the AU should return
kAudioUnitErr_InvalidPropertyValue if the host tries to read this value.
(2) If the value passed in is NULL, then if the AU had a parameter that it was in the process of mapping, it
should disregard that (stop listening to the MIDI messages to create a mapping) and discard the partially
mapped struct. If the value is NULL and the AU is not in the process of mapping, the AU can ignore the request.
At all times, the _AllMappings property will completely describe the current known state of the AU's mappings
of MIDI messages to parameters.
*/
/*
When mapping, it is recommended that LSB controllers are in general not mapped (ie. the controller range of 32 < 64)
as many host parsers will map 14 bit control values. If you know (or can present an option) that the host deals with
7 bit controllers only, then these controller ID's can be mapped of course.
*/
struct MIDIValueTransformer {
virtual double tolinear(double) = 0;
virtual double fromlinear(double) = 0;
#if DEBUG
// suppress warning
virtual ~MIDIValueTransformer() { }
#endif
};
struct MIDILinearTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return x; }
virtual double fromlinear(double x) { return x; }
};
struct MIDILogTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return log(std::max(x, .00001)); }
virtual double fromlinear(double x) { return exp(x); }
};
struct MIDIExpTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return exp(x); }
virtual double fromlinear(double x) { return log(std::max(x, .00001)); }
};
struct MIDISqrtTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
virtual double fromlinear(double x) { return x < 0. ? -(x * x) : x * x; }
};
struct MIDISquareTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return x < 0. ? -(x * x) : x * x; }
virtual double fromlinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
};
struct MIDICubeRtTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
virtual double fromlinear(double x) { return x * x * x; }
};
struct MIDICubeTransformer : public MIDIValueTransformer {
virtual double tolinear(double x) { return x * x * x; }
virtual double fromlinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
};
class CAAUMIDIMap : public AUParameterMIDIMapping {
public:
// variables for more efficient parsing of MIDI to Param value
Float32 mMinValue;
Float32 mMaxValue;
MIDIValueTransformer *mTransType;
// methods
static MIDIValueTransformer *GetTransformer (UInt32 inFlags);
CAAUMIDIMap() { memset(this, 0, sizeof(CAAUMIDIMap)); }
CAAUMIDIMap (const AUParameterMIDIMapping& inMap)
{
memset(this, 0, sizeof(CAAUMIDIMap));
memcpy (this, &inMap, sizeof(inMap));
}
CAAUMIDIMap (AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterID inParam)
{
memset(this, 0, sizeof(CAAUMIDIMap));
mScope = inScope;
mElement = inElement;
mParameterID = inParam;
}
bool IsValid () const { return mStatus != 0; }
// returns -1 if any channel bit is set
SInt32 Channel () const { return IsAnyChannel() ? -1 : (mStatus & 0xF); }
bool IsAnyChannel () const {
return mFlags & kAUParameterMIDIMapping_AnyChannelFlag;
}
// preserves the existing channel info in the status byte
// preserves any previously set mFlags value
void SetAnyChannel (bool inFlag)
{
if (inFlag)
mFlags |= kAUParameterMIDIMapping_AnyChannelFlag;
else
mFlags &= ~kAUParameterMIDIMapping_AnyChannelFlag;
}
bool IsAnyNote () const {
return (mFlags & kAUParameterMIDIMapping_AnyNoteFlag) != 0;
}
// preserves the existing key num in the mData1 byte
// preserves any previously set mFlags value
void SetAnyNote (bool inFlag)
{
if (inFlag)
mFlags |= kAUParameterMIDIMapping_AnyNoteFlag;
else
mFlags &= ~kAUParameterMIDIMapping_AnyNoteFlag;
}
bool IsToggle() const { return (mFlags & kAUParameterMIDIMapping_Toggle) != 0; }
void SetToggle (bool inFlag)
{
if (inFlag)
mFlags |= kAUParameterMIDIMapping_Toggle;
else
mFlags &= ~kAUParameterMIDIMapping_Toggle;
}
bool IsBipolar() const { return (mFlags & kAUParameterMIDIMapping_Bipolar) != 0; }
// inUseOnValue is valid ONLY if inFlag is true
void SetBipolar (bool inFlag, bool inUseOnValue = false)
{
if (inFlag) {
mFlags |= kAUParameterMIDIMapping_Bipolar;
if (inUseOnValue)
mFlags |= kAUParameterMIDIMapping_Bipolar_On;
else
mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
} else {
mFlags &= ~kAUParameterMIDIMapping_Bipolar;
mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
}
}
bool IsBipolar_OnValue () const { return (mFlags & kAUParameterMIDIMapping_Bipolar_On) != 0; }
bool IsSubRange () const { return (mFlags & kAUParameterMIDIMapping_SubRange) != 0; }
void SetSubRange (Float32 inStartValue, Float32 inStopValue)
{
mFlags |= kAUParameterMIDIMapping_SubRange;
mSubRangeMin = inStartValue;
mSubRangeMax = inStopValue;
}
void SetParamRange(Float32 minValue, Float32 maxValue)
{
mMinValue = minValue;
mMaxValue = maxValue;
}
// this will retain the subrange values previously set.
void SetSubRange (bool inFlag)
{
if (inFlag)
mFlags |= kAUParameterMIDIMapping_SubRange;
else
mFlags &= ~kAUParameterMIDIMapping_SubRange;
}
bool IsAnyValue() const{return !IsBipolar();}
bool IsOnValue() const{return IsBipolar_OnValue();}
bool IsOffValue() const{return IsBipolar();}
bool IsNoteOff () const { return ((mStatus & 0xF0) == 0x80); }
bool IsNoteOn () const { return ((mStatus & 0xF0) == 0x90); }
bool IsKeyPressure () const { return ((mStatus & 0xF0) == 0xA0); }
bool IsKeyEvent () const { return (mStatus > 0x7F) && (mStatus < 0xB0); }
bool IsPatchChange () const { return ((mStatus & 0xF0) == 0xC0); }
bool IsChannelPressure () const { return ((mStatus & 0xF0) == 0xD0); }
bool IsPitchBend () const { return ((mStatus & 0xF0) == 0xE0); }
bool IsControlChange () const { return ((mStatus & 0xF0) == 0xB0); }
void SetControllerOnValue(){SetBipolar(true,true);}
void SetControllerOffValue(){SetBipolar(true,false);}
void SetControllerAnyValue(){SetBipolar(false,false);}
// All of these Set calls will reset the mFlags field based on the
// anyChannel param value
void SetNoteOff (UInt8 key, SInt8 channel, bool anyChannel = false)
{
mStatus = 0x80 | (channel & 0xF);
mData1 = key;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
void SetNoteOn (UInt8 key, SInt8 channel, bool anyChannel = false)
{
mStatus = 0x90 | (channel & 0xF);
mData1 = key;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
void SetPolyKey (UInt8 key, SInt8 channel, bool anyChannel = false)
{
mStatus = 0xA0 | (channel & 0xF);
mData1 = key;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
void SetControlChange (UInt8 controllerID, SInt8 channel, bool anyChannel = false)
{
mStatus = 0xB0 | (channel & 0xF);
mData1 = controllerID;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
void SetPatchChange (UInt8 patchChange, SInt8 channel, bool anyChannel = false)
{
mStatus = 0xC0 | (channel & 0xF);
mData1 = patchChange;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
void SetChannelPressure (SInt8 channel, bool anyChannel = false)
{
mStatus = 0xD0 | (channel & 0xF);
mData1 = 0;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
void SetPitchBend (SInt8 channel, bool anyChannel = false)
{
mStatus = 0xE0 | (channel & 0xF);
mData1 = 0;
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
}
Float32 ParamValueFromMIDILinear (Float32 inLinearValue) const
{
Float32 low, high;
if (IsSubRange()){
low = mSubRangeMin;
high = mSubRangeMax;
}
else {
low = mMinValue;
high = mMaxValue;
}
// WE ARE ASSUMING YOU HAVE SET THIS UP PROPERLY!!!!! (or this will crash cause it will be NULL)
return (Float32)mTransType->fromlinear((inLinearValue * (high - low)) + low);
}
// The CALLER of this method must ensure that the status byte's MIDI Command (ignoring the channel) matches!!!
bool MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const;
void Print () const;
void Save (CFPropertyListRef &outData) const;
void Restore (CFDictionaryRef inData);
static void SaveAsMapPList (AudioUnit inUnit,
const AUParameterMIDIMapping * inMappings,
UInt32 inNumMappings,
CFPropertyListRef &outData,
CFStringRef inName = NULL);
// inNumMappings describes how much memory is allocated in outMappings
static void RestoreFromMapPList (const CFDictionaryRef inData,
AUParameterMIDIMapping * outMappings,
UInt32 inNumMappings);
static UInt32 NumberOfMaps (const CFDictionaryRef inData);
};
// these sorting operations sort for run-time efficiency based on the MIDI messages
inline bool operator== (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
{
// ignore channel first
return (((a.mStatus & 0xF0) == (b.mStatus & 0xF0))
&& (a.mData1 == b.mData1)
&& ((a.mStatus & 0xF) == (b.mStatus & 0xf)) // now compare the channel
&& (a.mParameterID == b.mParameterID)
&& (a.mElement == b.mElement)
&& (a.mScope == b.mScope));
// reserved field comparisons - ignored until/if they are used
}
inline bool operator< (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
{
if ((a.mStatus & 0xF0) != (b.mStatus & 0xF0))
return ((a.mStatus & 0xF0) < (b.mStatus & 0xF0));
if (a.mData1 != b.mData1)
return (a.mData1 < b.mData1);
if ((a.mStatus & 0xF) != (b.mStatus & 0xf)) // now compare the channel
return ((a.mStatus & 0xF) < (b.mStatus & 0xf));
// reserved field comparisons - ignored until/if they are used
// we're sorting this by MIDI, so we don't really care how the rest is sorted
return ((a.mParameterID < b.mParameterID)
&& (a.mElement < b.mElement)
&& (a.mScope < b.mScope));
}
class CompareMIDIMap {
int compare (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
{
if ((a.mStatus & 0xF0) < (b.mStatus & 0xF0))
return -1;
if ((a.mStatus & 0xF0) > (b.mStatus & 0xF0))
return 1;
// note event
if (a.mStatus < 0xB0 || a.mStatus >= 0xD0)
return 0;
if (a.mData1 > b.mData1) return 1;
if (a.mData1 < b.mData1) return -1;
return 0;
}
public:
bool operator() (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
return compare (a, b) < 0;
}
bool Finish (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
return compare (a, b) != 0;
}
};
/*
usage: To find potential mapped events for a given status byte, where mMMapEvents is a sorted vec
CompareMIDIMap comparObj;
sortVecIter lower_iter = std::lower_bound(mMMapEvents.begin(), mMMapEvents.end(), inStatusByte, compareObj);
for (;lower_iter < mMMapEvents.end(); ++lower_iter) {
// then, see if we go out of the status byte range, using the Finish method
if (compareObj.Finish(map, tempMap)) // tempMap is a CAAUMIDIMap object with the status/dataByte 1 set
break;
// ...
}
in the for loop you call the MIDI_Matches call, to see if the MIDI event matches a given AUMIDIParam mapping
special note: you HAVE to transform note on (with vel zero) events to the note off status byte
*/
#endif

View File

@@ -0,0 +1,233 @@
/*
File: CAAUMIDIMapManager.cpp
Abstract: CAAUMIDIMapManager.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CAAUMIDIMapManager.h"
#include <AudioToolbox/AudioUnitUtilities.h>
CAAUMIDIMapManager::CAAUMIDIMapManager()
{
hotMapping = false;
}
static void FillInMap (CAAUMIDIMap &map, AUBase &That)
{
AudioUnitParameterInfo info;
That.GetParameterInfo (map.mScope, map.mParameterID, info);
if (map.IsSubRange()) {
map.mMinValue = map.mSubRangeMin;
map.mMaxValue = map.mSubRangeMax;
} else {
map.mMinValue = info.minValue;
map.mMaxValue = info.maxValue;
}
map.mTransType = CAAUMIDIMap::GetTransformer(info.flags);
}
OSStatus CAAUMIDIMapManager::SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That)
{
for (unsigned int i = 0; i < inNumMaps; ++i)
{
CAAUMIDIMap map(maps[i]);
FillInMap (map, That);
int idx = FindParameterIndex (maps[i]);
if (idx > -1)
mParameterMaps.erase(mParameterMaps.begin() + idx);
// least disruptive place to put this is at the end
mParameterMaps.push_back(map);
}
std::sort(mParameterMaps.begin(), mParameterMaps.end(), CompareMIDIMap());
return noErr;
}
void CAAUMIDIMapManager::GetHotParameterMap(AUParameterMIDIMapping &outMap )
{
outMap = mHotMap;
}
void CAAUMIDIMapManager::SortedRemoveFromParameterMaps(AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange)
{
if (hotMapping) {
hotMapping = false;
}
outMapDidChange = false;
for (unsigned int i = 0; i < inNumMaps; ++i) {
int idx = FindParameterIndex (maps[i]);
if (idx > -1) {
//mParameterMaps[idx].Print();
mParameterMaps.erase(mParameterMaps.begin() + idx);
outMapDidChange = true;
}
}
}
void CAAUMIDIMapManager::ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That)
{
mParameterMaps.clear();
for (unsigned int i = 0; i < inNumMaps; ++i) {
CAAUMIDIMap mapping(inMappings[i]);
FillInMap (mapping, That);
mParameterMaps.push_back (mapping);
}
std::sort(mParameterMaps.begin(),mParameterMaps.end(), CompareMIDIMap());
}
bool CAAUMIDIMapManager::HandleHotMapping(UInt8 inStatus,
UInt8 inChannel,
UInt8 inData1,
AUBase &That)
{ //used to set the hot map info
if (inStatus == 0xf0) return false;
if (!hotMapping) return false;
hotMapping = false;
mHotMap.mStatus = inStatus | inChannel;
mHotMap.mData1 = inData1;
SortedInsertToParamaterMaps (&mHotMap, 1, That);
return true;
}
#if DEBUG
void CAAUMIDIMapManager::Print()
{
for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) {
CAAUMIDIMap* listmap = &(*i);
listmap->Print();
}
}
#endif // DEBUG
void CAAUMIDIMapManager::GetMaps(AUParameterMIDIMapping* maps)
{
int i = 0;
for ( ParameterMaps::iterator iter = mParameterMaps.begin(); iter < mParameterMaps.end(); ++iter, ++i) {
AUParameterMIDIMapping &listmap = (*iter);
maps[i] = listmap;
}
}
int CAAUMIDIMapManager::FindParameterIndex (AUParameterMIDIMapping &inMap)
{
//used to get back hot mapping and one at a time maps, for ui
int idx = 0;
for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) {
CAAUMIDIMap & listmap = (*i);
if ( (listmap.mParameterID == inMap.mParameterID) &&
(listmap.mScope == inMap.mScope) &&
(listmap.mElement == inMap.mElement) )
{
return idx;
}
idx++;
}
return -1;
}
bool CAAUMIDIMapManager::FindParameterMapEventMatch( UInt8 inStatus,
UInt8 inChannel,
UInt8 inData1,
UInt8 inData2,
UInt32 inBufferOffset,
AUBase& inAUBase)
{
bool ret_value = false;
if (inStatus == 0x90 && !inData2)
inStatus = 0x80 | inChannel;
//used to test for midi matches once map is made
CAAUMIDIMap tempMap;
tempMap.mStatus = inStatus | inChannel;
tempMap.mData1 = inData1;
CompareMIDIMap compareObj;
AudioUnitEvent event;
event.mEventType = kAudioUnitEvent_ParameterValueChange;
event.mArgument.mParameter.mAudioUnit = inAUBase.GetComponentInstance();
ParameterMaps::iterator lower_iter =
std::lower_bound(mParameterMaps.begin(), mParameterMaps.end(), tempMap, compareObj);
while (lower_iter < mParameterMaps.end())
{
CAAUMIDIMap & map = (*lower_iter);
if (compareObj.Finish(map, tempMap))
break;
Float32 value;
if (map.MIDI_Matches(inChannel, inData1, inData2, value))
{
inAUBase.SetParameter ( map.mParameterID, map.mScope, map.mElement,
map.ParamValueFromMIDILinear(value), inBufferOffset);
event.mArgument.mParameter.mParameterID = map.mParameterID;
event.mArgument.mParameter.mScope = map.mScope;
event.mArgument.mParameter.mElement = map.mElement;
AUEventListenerNotify(NULL, NULL, &event);
ret_value = true;
}
++lower_iter;
}
return ret_value;
}

View File

@@ -0,0 +1,102 @@
/*
File: CAAUMIDIMapManager.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __CAAUMIDIMapManager_h_
#define __CAAUMIDIMapManager_h_
#include "AUBase.h"
#include "CAAUMIDIMap.h"
#include <vector>
#include <AudioToolbox/AudioUnitUtilities.h>
class CAAUMIDIMapManager {
protected:
typedef std::vector<CAAUMIDIMap> ParameterMaps;
ParameterMaps mParameterMaps;
bool hotMapping;
AUParameterMIDIMapping mHotMap;
public:
CAAUMIDIMapManager();
UInt32 NumMaps(){return static_cast<UInt32>(mParameterMaps.size());}
void GetMaps(AUParameterMIDIMapping* maps);
int FindParameterIndex(AUParameterMIDIMapping &map);
void GetHotParameterMap(AUParameterMIDIMapping &outMap);
void SortedRemoveFromParameterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange);
OSStatus SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That);
void ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That);
bool IsHotMapping(){return hotMapping;}
void SetHotMapping (AUParameterMIDIMapping &inMap){hotMapping = true; mHotMap = inMap; }
bool HandleHotMapping( UInt8 inStatus,
UInt8 inChannel,
UInt8 inData1,
AUBase &That);
bool FindParameterMapEventMatch(UInt8 inStatus,
UInt8 inChannel,
UInt8 inData1,
UInt8 inData2,
UInt32 inBufferOffset,
AUBase& inAUBase);
#if DEBUG
void Print();
#endif
};
#endif

View File

@@ -0,0 +1,400 @@
/*
File: CAAUParameter.cpp
Abstract: CAAUParameter.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CAAUParameter.h"
CAAUParameter::CAAUParameter()
{
memset(this, 0, sizeof(CAAUParameter));
}
CAAUParameter::CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
{
memset(this, 0, sizeof(CAAUParameter));
Init (au, param, scope, element);
}
CAAUParameter::CAAUParameter (AudioUnitParameter &inParam)
{
memset(this, 0, sizeof(CAAUParameter));
Init (inParam.mAudioUnit, inParam.mParameterID, inParam.mScope, inParam.mElement);
}
CAAUParameter::CAAUParameter(const CAAUParameter &a)
{
memset(this, 0, sizeof(CAAUParameter));
*this = a;
}
CAAUParameter & CAAUParameter::operator = (const CAAUParameter &a)
{
if (mParamName) CFRelease(mParamName);
if (mParamTag) CFRelease(mParamTag);
if (mNamedParams) CFRelease(mNamedParams);
memcpy(this, &a, sizeof(CAAUParameter));
if (mParamName) CFRetain(mParamName);
if (mParamTag) CFRetain(mParamTag);
if (mNamedParams) CFRetain(mNamedParams);
return *this;
}
CAAUParameter::~CAAUParameter()
{
if (mParamName) CFRelease(mParamName);
if (mParamTag) CFRelease(mParamTag);
if (mNamedParams) CFRelease (mNamedParams);
}
void CAAUParameter::Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
{
mAudioUnit = au;
mParameterID = param;
mScope = scope;
mElement = element;
UInt32 propertySize = sizeof(mParamInfo);
OSStatus err = AudioUnitGetProperty(au, kAudioUnitProperty_ParameterInfo,
scope, param, &mParamInfo, &propertySize);
if (err)
memset(&mParamInfo, 0, sizeof(mParamInfo));
if (mParamInfo.flags & kAudioUnitParameterFlag_HasCFNameString) {
mParamName = mParamInfo.cfNameString;
if (!(mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease))
CFRetain (mParamName);
} else
mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8);
const char* str = 0;
switch (mParamInfo.unit)
{
case kAudioUnitParameterUnit_Boolean:
str = "T/F";
break;
case kAudioUnitParameterUnit_Percent:
case kAudioUnitParameterUnit_EqualPowerCrossfade:
str = "%";
break;
case kAudioUnitParameterUnit_Seconds:
str = "Secs";
break;
case kAudioUnitParameterUnit_SampleFrames:
str = "Samps";
break;
case kAudioUnitParameterUnit_Phase:
case kAudioUnitParameterUnit_Degrees:
str = "Degr.";
break;
case kAudioUnitParameterUnit_Hertz:
str = "Hz";
break;
case kAudioUnitParameterUnit_Cents:
case kAudioUnitParameterUnit_AbsoluteCents:
str = "Cents";
break;
case kAudioUnitParameterUnit_RelativeSemiTones:
str = "S-T";
break;
case kAudioUnitParameterUnit_MIDINoteNumber:
case kAudioUnitParameterUnit_MIDIController:
str = "MIDI";
//these are inclusive, so add one value here
mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
break;
case kAudioUnitParameterUnit_Decibels:
str = "dB";
break;
case kAudioUnitParameterUnit_MixerFaderCurve1:
case kAudioUnitParameterUnit_LinearGain:
str = "Gain";
break;
case kAudioUnitParameterUnit_Pan:
str = "L/R";
break;
case kAudioUnitParameterUnit_Meters:
str = "Mtrs";
break;
case kAudioUnitParameterUnit_Octaves:
str = "8ve";
break;
case kAudioUnitParameterUnit_BPM:
str = "BPM";
break;
case kAudioUnitParameterUnit_Beats:
str = "Beats";
break;
case kAudioUnitParameterUnit_Milliseconds:
str = "msecs";
break;
case kAudioUnitParameterUnit_Ratio:
str = "Ratio";
break;
case kAudioUnitParameterUnit_Indexed:
{
propertySize = sizeof(mNamedParams);
err = AudioUnitGetProperty (au,
kAudioUnitProperty_ParameterValueStrings,
scope,
param,
&mNamedParams,
&propertySize);
if (!err && mNamedParams) {
mNumIndexedParams = CFArrayGetCount(mNamedParams);
} else {
//these are inclusive, so add one value here
mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
}
str = NULL;
}
break;
case kAudioUnitParameterUnit_CustomUnit:
{
CFStringRef unitName = mParamInfo.unitName;
static char paramStr[256];
CFStringGetCString (unitName, paramStr, 256, kCFStringEncodingUTF8);
if (mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease)
CFRelease (unitName);
str = paramStr;
break;
}
case kAudioUnitParameterUnit_Generic:
case kAudioUnitParameterUnit_Rate:
default:
str = NULL;
break;
}
if (str)
mParamTag = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
else
mParamTag = NULL;
}
Float32 CAAUParameter::GetValue() const
{
Float32 value = 0.;
//OSStatus err =
AudioUnitGetParameter(mAudioUnit, mParameterID, mScope, mElement, &value);
return value;
}
CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue,
const CAAUParameter * inParameter,
UInt32 inDigits,
UInt32 minDigits) {
if (!inParameter) return nil;
AudioUnitParameterInfo info = inParameter->ParamInfo();
int pow10;
switch (info.unit) {
case kAudioUnitParameterUnit_Hertz:
// number of significant digits based on value
pow10 = int(log10(fmax(inParameterValue, .000001)));
break;
default:
// number of significant digits based on parameter range
pow10 = int(log10(fmax(double(info.maxValue - info.minValue), .000001)));
break;
}
// pow10 range nDigitsAfterDecimal
// -2 .0100-.0999 4
// -1 .100-.999 3
// 0 1.00-9.99 2
// 1 10.0-99.9 1
// 2 100-999 0
// 3 1000-9990 -1
// 4 10000-99900 -2
int nDigitsAfterDecimal = inDigits - (pow10 + 1);
if (nDigitsAfterDecimal < 0)
nDigitsAfterDecimal = 0; // the least number of digits possible is zero
if (info.flags & kAudioUnitParameterFlag_IsHighResolution)
nDigitsAfterDecimal = 4;
CFLocaleRef currentLocale = CFLocaleCopyCurrent();
CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle);
CFNumberRef maxFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal);
if (nDigitsAfterDecimal > 0)
nDigitsAfterDecimal = minDigits;
CFNumberRef minFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal);
CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMinFractionDigits, minFractionDigits);
CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMaxFractionDigits, maxFractionDigits);
CFStringRef formattedNumberString = CFNumberFormatterCreateStringWithValue (NULL, numberFormatter, kCFNumberDoubleType, &inParameterValue);
CFRelease(currentLocale);
CFRelease(numberFormatter);
CFRelease(maxFractionDigits);
CFRelease(minFractionDigits);
return formattedNumberString;
}
CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue,
const CAAUParameter * inParameter,
UInt32 inDigits) {
return CreateLocalizedStringForParameterValue (inParameterValue, inParameter, inDigits, 1);
}
double ValueForLocalizedParameterString (CFStringRef string, const CAAUParameter * inParameter) {
CFLocaleRef currentLocale = CFLocaleCopyCurrent();
CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle);
double value = 0;
Boolean worked = CFNumberFormatterGetValueFromString (numberFormatter, string, NULL, kCFNumberDoubleType, &value);
CFRelease(currentLocale);
CFRelease(numberFormatter);
if (worked)
return value;
else {
AudioUnitParameterInfo info = inParameter->ParamInfo();
return info.defaultValue;
}
}
CFStringRef CAAUParameter::GetStringFromValueCopy(const Float32 *value) const
{
if (HasNamedParams())
{
Float32 val = (value == NULL ? GetValue() : *value);
int index = int(mParamInfo.minValue) + int(val);
CFStringRef str = GetParamName (index);
if (str) {
CFRetain (str);
return str;
}
}
else if (ValuesHaveStrings())
{
AudioUnitParameterStringFromValue stringValue;
stringValue.inParamID = mParameterID;
stringValue.inValue = value;
stringValue.outString = NULL;
UInt32 propertySize = sizeof(stringValue);
OSStatus err = AudioUnitGetProperty (mAudioUnit,
kAudioUnitProperty_ParameterStringFromValue,
mScope,
0,
&stringValue,
&propertySize);
if (!err && stringValue.outString != NULL)
return stringValue.outString;
}
Float32 val = (value == NULL ? GetValue() : *value);
AudioUnitParameterUnit unit = this->ParamInfo().unit;
if (unit == kAudioUnitParameterUnit_Cents || unit == kAudioUnitParameterUnit_AbsoluteCents)
return CreateLocalizedStringForParameterValue(val, this, 4, 0);
else
return CreateLocalizedStringForParameterValue(val, this, 4);
}
Float32 CAAUParameter::GetValueFromString(CFStringRef str) const
{
if (ValuesHaveStrings())
{
AudioUnitParameterValueFromString valueString;
valueString.inParamID = mParameterID;
valueString.inString = str;
UInt32 propertySize = sizeof(valueString);
OSStatus err = AudioUnitGetProperty (mAudioUnit,
kAudioUnitProperty_ParameterValueFromString,
mScope,
0,
&valueString,
&propertySize);
if (!err) {
return valueString.outValue;
}
}
return (Float32) ValueForLocalizedParameterString(str, this);
}
void CAAUParameter::SetValue( AUParameterListenerRef inListener,
void * inObject,
Float32 inValue) const
{
// clip inValue as: maxValue >= inValue >= minValue before setting
Float32 valueToSet = inValue;
if (valueToSet > mParamInfo.maxValue)
valueToSet = mParamInfo.maxValue;
if (valueToSet < mParamInfo.minValue)
valueToSet = mParamInfo.minValue;
AUParameterSet(inListener, inObject, this, valueToSet, 0);
}
#if DEBUG
void CAAUParameter::Print() const
{
UInt32 clump = 0;
GetClumpID (clump);
UInt32 len = static_cast<UInt32>(CFStringGetLength(mParamName));
char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars
if (!CFStringGetCString (mParamName, chars, len * 2, kCFStringEncodingUTF8))
chars[0] = 0;
printf ("ID: %ld, Clump: %u, Name: %s\n", (long unsigned int) mParameterID, (unsigned int) clump, chars);
free (chars);
}
#endif

View File

@@ -0,0 +1,191 @@
/*
File: CAAUParameter.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __CAAUParameter_h__
#define __CAAUParameter_h__
#include <AudioToolbox/AudioUnitUtilities.h>
// ____________________________________________________________________________
// CAAUParameter
// complete parameter specification
/*! @class CAAUParameter */
class CAAUParameter : public AudioUnitParameter {
public:
/*! @ctor CAAUParameter.0 */
CAAUParameter();
/*! @ctor CAAUParameter.1 */
CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element);
/*! @ctor CAAUParameter.2 */
CAAUParameter(AudioUnitParameter &inParam);
/*! @ctor CAAUParameter.3 */
CAAUParameter(const CAAUParameter &a);
/*! @dtor ~CAAUParameter */
~CAAUParameter();
/*! @method operator <@ */
bool operator < (const CAAUParameter &a) const
{
return memcmp(this, &a, sizeof(AudioUnitParameter)) < 0;
}
/*! @method operator ==@ */
bool operator == (const CAAUParameter &a) const
{
return !memcmp(this, &a, sizeof(AudioUnitParameter));
}
/*! @method operator =@ */
CAAUParameter & operator = (const CAAUParameter &a);
/*! @method GetValue */
Float32 GetValue() const;
/*! @method SetValue */
void SetValue( AUParameterListenerRef inListener,
void * inObject,
Float32 inValue) const;
/*! @method GetName */
CFStringRef GetName() const { return mParamName; }
// borrowed reference!
/*! @method GetStringFromValueCopy */
CFStringRef GetStringFromValueCopy(const Float32 *value = NULL) const;
// returns a copy of the name of the current parameter value
// or null if there is no name associated
// caller must release
/*! @method ValuesHaveStrings */
bool ValuesHaveStrings () const
{
return (mParamInfo.flags & kAudioUnitParameterFlag_ValuesHaveStrings) != 0;
}
/*! @method GetValueFromString */
Float32 GetValueFromString (CFStringRef str) const;
// caller must release
/*! @method ParamInfo */
const AudioUnitParameterInfo &
ParamInfo() const { return mParamInfo; }
/*! @method GetParamTag */
CFStringRef GetParamTag() const { return mParamTag; }
// this may return null! -
// in which case there is no descriptive tag for the parameter
/*! @method GetParamName */
CFStringRef GetParamName (int inIndex) const
// this can return null if there is no name for the parameter
{
return (mNamedParams && inIndex < mNumIndexedParams)
? (CFStringRef) CFArrayGetValueAtIndex(mNamedParams, inIndex)
: 0;
}
/*! @method GetNumIndexedParams */
int GetNumIndexedParams () const { return mNumIndexedParams; }
/*! @method IsIndexedParam */
bool IsIndexedParam () const { return mNumIndexedParams != 0; }
/*! @method HasNamedParams */
bool HasNamedParams () const { return IsIndexedParam() && mNamedParams; }
/*! @method GetClumpID */
bool GetClumpID (UInt32 &outClumpID) const
{
if (mParamInfo.flags & kAudioUnitParameterFlag_HasClump) {
outClumpID = mParamInfo.clumpID;
return true;
}
return false;
}
/*! @method HasDisplayTransformation */
bool HasDisplayTransformation () const
{
return GetAudioUnitParameterDisplayType (mParamInfo.flags);
}
/*! @method IsExpert */
bool IsExpert () const
{
return mParamInfo.flags & kAudioUnitParameterFlag_ExpertMode;
}
#if DEBUG
void Print () const;
#endif
// these methods are defined in CAPersistence.cpp
// they will persist and restore only the scope, element and param ID's of the AudioUnitParameter
// however, this is sufficient to be able to save/restore a CAAUParameter object
void Save (CFPropertyListRef &outData) const;
static void Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData);
static OSStatus Restore (const CFPropertyListRef inData, AudioUnitParameter &outParam);
protected:
// cached parameter info
/*! @var mParamInfo */
AudioUnitParameterInfo mParamInfo;
/*! @var mParamName */
CFStringRef mParamName;
/*! @var mParamTag */
CFStringRef mParamTag;
/*! @var mNumIndexedParams */
short mNumIndexedParams;
/*! @var mNamedParams */
CFArrayRef mNamedParams;
private:
void Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element);
};
#endif // __CAAUParameter_h__

View File

@@ -0,0 +1,707 @@
/*
File: CAAUProcessor.cpp
Abstract: CAAUProcessor.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CAAUProcessor.h"
#include "CAXException.h"
static OSStatus SilenceInputCallback (void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
AudioBuffer *buf = ioData->mBuffers;
for (UInt32 i = ioData->mNumberBuffers; i--; ++buf)
memset((Byte *)buf->mData, 0, buf->mDataByteSize);
//provide a hint that our input data is silent.
*ioActionFlags &= kAudioUnitRenderAction_OutputIsSilence;
return noErr;
}
static AURenderCallbackStruct sSilentCallback = { SilenceInputCallback, NULL };
CAAUProcessor::CAAUProcessor (const CAComponent& inComp)
: mPreflightABL(NULL)
{
OSStatus result = CAAudioUnit::Open (inComp, mUnit);
if (result)
throw result;
memset (&mUserCallback, 0, sizeof (AURenderCallbackStruct));
mMaxTailTime = 10.;
}
CAAUProcessor::~CAAUProcessor ()
{
if (mPreflightABL)
delete mPreflightABL;
}
inline OSStatus SetInputCallback (CAAudioUnit &inUnit, AURenderCallbackStruct &inInputCallback)
{
return inUnit.SetProperty (kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&inInputCallback,
sizeof(inInputCallback));
}
static AURenderCallbackStruct sRenderCallback;
static OSStatus PrerollRenderProc ( void * /*inRefCon*/,
AudioUnitRenderActionFlags * /*inActionFlags*/,
const AudioTimeStamp * /*inTimeStamp*/,
UInt32 /*inBusNumber*/,
UInt32 /*inNumFrames*/,
AudioBufferList *ioData)
{
AudioBuffer *buf = ioData->mBuffers;
for (UInt32 i = ioData->mNumberBuffers; i--; ++buf)
memset((Byte *)buf->mData, 0, buf->mDataByteSize);
return noErr;
}
OSStatus Preroll (CAAudioUnit & inAU, UInt32 inFrameSize)
{
CAStreamBasicDescription desc;
OSStatus result = inAU.GetFormat (kAudioUnitScope_Input, 0, desc);
bool hasInput = false;
//we have input
if (result == noErr)
{
sRenderCallback.inputProc = PrerollRenderProc;
sRenderCallback.inputProcRefCon = 0;
result = inAU.SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
0, &sRenderCallback, sizeof(sRenderCallback));
if (result) return result;
hasInput = true;
}
AudioUnitRenderActionFlags flags = 0;
AudioTimeStamp time;
memset (&time, 0, sizeof(time));
time.mFlags = kAudioTimeStampSampleTimeValid;
CAStreamBasicDescription outputFormat;
ca_require_noerr (result = inAU.GetFormat (kAudioUnitScope_Output, 0, outputFormat), home);
{
AUOutputBL list (outputFormat, inFrameSize);
list.Prepare ();
result = inAU.Render (&flags, &time, 0, inFrameSize, list.ABL());
if (result) { printf("A result %d\n", (int)result); goto home; }
}
home:
if (hasInput) {
// remove our installed callback
sRenderCallback.inputProc = 0;
sRenderCallback.inputProcRefCon = 0;
inAU.SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
0, &sRenderCallback, sizeof(sRenderCallback));
}
return result;
}
OSStatus CAAUProcessor::EstablishInputCallback (AURenderCallbackStruct &inInputCallback)
{
OSStatus result = SetInputCallback (mUnit, inInputCallback);
if (!result)
memcpy (&mUserCallback, &inInputCallback, sizeof(AURenderCallbackStruct));
else
memset (&mUserCallback, 0, sizeof (AURenderCallbackStruct));
return result;
}
OSStatus CAAUProcessor::SetAUPreset (CFPropertyListRef inPreset)
{
return mUnit.SetProperty (kAudioUnitProperty_ClassInfo,
kAudioUnitScope_Global,
0,
&inPreset,
sizeof(inPreset));
}
OSStatus CAAUProcessor::SetAUPresetIndex (SInt32 inPresetIndex)
{
AUPreset aup;
aup.presetName = NULL;
aup.presetNumber = inPresetIndex;
return mUnit.SetPresentPreset(aup);
}
OSStatus CAAUProcessor::SetParameter (AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
Float32 value, UInt32 bufferOffsetFrames)
{
return mUnit.SetParameter(inID, scope, element, value, bufferOffsetFrames);
}
UInt32 CAAUProcessor::MaxFramesPerRender () const
{
UInt32 maxFrames;
UInt32 propSize = sizeof (maxFrames);
if (mUnit.GetProperty (kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, 0, &maxFrames, &propSize))
{
return 0;
}
return maxFrames;
}
OSStatus CAAUProcessor::SetMaxFramesPerRender (UInt32 inMaxFrames)
{
return mUnit.SetProperty (kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, 0, &inMaxFrames, sizeof(inMaxFrames));
}
OSStatus CAAUProcessor::Initialize (const CAStreamBasicDescription &inInputDesc,
const CAStreamBasicDescription &inOutputDesc,
UInt64 inNumInputSamples)
{
return DoInitialisation (inInputDesc, inOutputDesc, inNumInputSamples, MaxFramesPerRender());
}
OSStatus CAAUProcessor::Reinitialize (UInt32 inNewMaxFrames)
{
OSStatus result;
CAStreamBasicDescription inputDesc, outputDesc;
ca_require_noerr (result = mUnit.GetFormat (kAudioUnitScope_Input, 0, inputDesc), home);
ca_require_noerr (result = mUnit.GetFormat (kAudioUnitScope_Output, 0, outputDesc), home);
ca_require_noerr (result = DoInitialisation (inputDesc, outputDesc, mNumInputSamples, inNewMaxFrames), home);
home:
return result;
}
OSStatus CAAUProcessor::DoInitialisation (const CAStreamBasicDescription &inInputFormat,
const CAStreamBasicDescription &inOutputFormat,
UInt64 inNumInputSamples,
UInt32 inMaxFrames)
{
OSStatus result;
if (inNumInputSamples == 0 && IsOfflineAU())
return kAudioUnitErr_InvalidOfflineRender;
mNumInputSamples = inNumInputSamples;
// first check that we can do this number of channels
if (mUnit.CanDo (inInputFormat.NumberChannels(), inOutputFormat.NumberChannels()) == false)
ca_require_noerr (result = kAudioUnitErr_FailedInitialization, home);
// just uninitialise the AU as a matter of course
ca_require_noerr (result = mUnit.Uninitialize(), home);
ca_require_noerr (result = mUnit.SetFormat (kAudioUnitScope_Input, 0, inInputFormat), home);
ca_require_noerr (result = mUnit.SetFormat (kAudioUnitScope_Output, 0, inOutputFormat), home);
ca_require_noerr (result = SetMaxFramesPerRender (inMaxFrames), home);
#if !TARGET_OS_IPHONE
// if we're any AU but an offline AU, we should tell it that we've processing offline
if (!IsOfflineAU()) {
UInt32 isOffline = (IsOfflineContext() ? 1 : 0);
// don't care whether this succeeds of fails as many AU's don't care about this
// but the ones that do its important that they are told their render context
mUnit.SetProperty (kAudioUnitProperty_OfflineRender, kAudioUnitScope_Global, 0, &isOffline, sizeof(isOffline));
} else {
// tell the offline unit how many input samples we wish to process...
mUnit.SetProperty (kAudioUnitOfflineProperty_InputSize,
kAudioUnitScope_Global, 0,
&mNumInputSamples, sizeof(mNumInputSamples));
}
#endif
ca_require_noerr (result = mUnit.Initialize(), home);
ca_require_noerr (result = SetInputCallback (mUnit, mUserCallback), home);
// finally reset our time stamp
// the time stamp we use with the AU Render - only sample count is valid
memset (&mRenderTimeStamp, 0, sizeof(mRenderTimeStamp));
mRenderTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
// now, if we're NOT an offline AU, preflighting is not required
// if we are an offline AU, we should preflight.. an offline AU will tell us when its preflighting is done
mPreflightDone = false;
if (mPreflightABL) {
delete mPreflightABL;
mPreflightABL = NULL;
}
mPreflightABL = new AUOutputBL (inOutputFormat);
mLastPercentReported = 0;
home:
return result;
}
void CAAUProcessor::CalculateRemainderSamples (Float64 inSampleRate)
{
mLatencySamples = 0;
mTailSamplesToProcess = 0;
mTailSamples = 0;
mTailSamplesRemaining = 0;
return;
// nothing to do because we're not processing offline
if (IsOfflineContext() == false) return;
// because an offline unit has some indeterminancy about what it does with the input samples
// it is *required* to deal internally with both latency and tail
if (!IsOfflineAU())
{
// when offline we need to deal with both latency and tail
// if the AU has latency - how many samples at the start will be zero?
// we'll end up chucking these away.
Float64 renderTimeProps;
UInt32 propSize = sizeof (renderTimeProps);
OSStatus result = mUnit.GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,
&renderTimeProps, &propSize);
Float64 latencySamples = 0;
if (result == noErr) // we have latency to deal with - its reported in seconds
latencySamples = renderTimeProps * inSampleRate;
// AU tail
// if the AU has a tail - we'll pull that many zeroes through at the end to flush
// out this tail - think of a decaying digital delay or reverb...
result = mUnit.GetProperty (kAudioUnitProperty_TailTime, kAudioUnitScope_Global, 0,
&renderTimeProps, &propSize);
if (renderTimeProps > mMaxTailTime)
renderTimeProps = mMaxTailTime;
Float64 tailSamples = 0;
if (result == noErr)
tailSamples = renderTimeProps * inSampleRate;
// this dictates how many samples at the end we need to pull through...
// we add latency to tail because we throw the latency samples away from the start of the rendering
// and we have to pull that many samples after the end of course to get the last of the original data
// then to that is added the tail of the effect...
mTailSamplesToProcess = UInt32(tailSamples + latencySamples);
mTailSamples = UInt32(tailSamples);
mLatencySamples = UInt32(latencySamples);
}
}
#if !TARGET_OS_IPHONE
CFStringRef CAAUProcessor::GetOLPreflightName () const
{
if (OfflineAUNeedsPreflight())
{
CFStringRef str;
UInt32 size = sizeof(str);
OSStatus result = mUnit.GetProperty (kAudioUnitOfflineProperty_PreflightName,
kAudioUnitScope_Global, 0,
&str, &size);
return result ? NULL : str;
}
return NULL; // says NO to preflighting
}
bool CAAUProcessor::OfflineAUNeedsPreflight () const
{
if (IsOfflineAU()) {
UInt32 preflightRequirements;
UInt32 size = sizeof(preflightRequirements);
OSStatus result = mUnit.GetProperty (kAudioUnitOfflineProperty_PreflightRequirements,
kAudioUnitScope_Global, 0,
&preflightRequirements, &size);
if (result)
return false;
return preflightRequirements;
}
return false;
}
#endif
OSStatus CAAUProcessor::Preflight (bool inProcessPreceedingTail)
{
printf(">>>>CAAUProcessor::Preflight\n");
//we're preflighting again, so reset ourselves
if (mPreflightDone) {
mPreflightDone = false;
// the time stamp we use with the AU Render - only sample count is valid
memset (&mRenderTimeStamp, 0, sizeof(mRenderTimeStamp));
mRenderTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
mUnit.GlobalReset();
}
Float64 sampleRate;
OSStatus result = mUnit.GetSampleRate (kAudioUnitScope_Output, 0, sampleRate);
CalculateRemainderSamples (sampleRate);
UInt32 numFrames = MaxFramesPerRender();
if (numFrames == 0)
return kAudioUnitErr_InvalidProperty;
if (!IsOfflineAU())
{
if ((IsOfflineContext() == false && inProcessPreceedingTail) || IsOfflineContext())
{
// re-establish the user's input callback
ca_require_noerr (result = SetInputCallback (mUnit, mUserCallback), home);
// Consume the number of input samples indicated by the AU's latency or tail
// based on whether the AU is being used in an offline context or not.
UInt32 latSamps = IsOfflineContext() ? mLatencySamples : mTailSamples;
printf("latSamps %d\n", (int)latSamps);
latSamps = 0;
while (latSamps > 0)
{
if (latSamps < numFrames)
numFrames = latSamps;
// process the samples (the unit's input callback will read the samples
// from the file and convert them to float for processing
AudioUnitRenderActionFlags renderFlags = 0;
mPreflightABL->Prepare();
result = mUnit.Render (&renderFlags, &mRenderTimeStamp, 0, numFrames, mPreflightABL->ABL());
if (result) { printf("B result %d\n", (int)result); goto home; }
mRenderTimeStamp.mSampleTime += numFrames;
latSamps -= numFrames;
}
if (IsOfflineContext())
mRenderTimeStamp.mSampleTime = mLatencySamples;
}
else
{
// processing real-time but not processing preceeding tail, so we should preroll the AU
ca_require_noerr (result = Preroll(mUnit, numFrames), home);
// re-establish the user's input callback
ca_require_noerr (result = SetInputCallback (mUnit, mUserCallback), home);
mRenderTimeStamp.mSampleTime = 0;
}
}
#if !TARGET_OS_IPHONE
else
{
// re-establish the user's input callback
ca_require_noerr (result = SetInputCallback (mUnit, mUserCallback), home);
UInt32 preflightRequirements;
UInt32 size; size = sizeof(preflightRequirements);
ca_require_noerr (result = mUnit.GetProperty (kAudioUnitOfflineProperty_PreflightRequirements,
kAudioUnitScope_Global, 0,
&preflightRequirements, &size), home);
// 0 indicates none, otherwise optional or required -> we do it for either
if (preflightRequirements)
{
for (;;) {
// here we need to do the preflight loop - we don't expect any data back, but have to
// give the offline unit all of its input data to allow it to prepare its processing
AudioUnitRenderActionFlags renderFlags = kAudioOfflineUnitRenderAction_Preflight;
mPreflightABL->Prepare();
result = mUnit.Render (&renderFlags, &mRenderTimeStamp, 0, numFrames, mPreflightABL->ABL());
if (result) { printf("C result %d\n", (int)result); goto home; }
mRenderTimeStamp.mSampleTime += numFrames;
if (renderFlags & kAudioOfflineUnitRenderAction_Complete)
break;
}
}
// the time stamp we use with the AU Render - only sample count is valid
mRenderTimeStamp.mSampleTime = 0;
}
#endif
if (result == noErr) {
mPreflightDone = true;
}
home:
printf("<<<<CAAUProcessor::Preflight\n");
return result;
}
#if !TARGET_OS_IPHONE
OSStatus CAAUProcessor::OfflineAUPreflight (UInt32 inNumFrames, bool &outIsDone)
{
if (!IsOfflineAU())
return -50/*paramErr*/;
if (mNumInputSamples == 0)
return -50/*paramErr*/;
UInt32 preflightRequirements;
UInt32 size = sizeof(preflightRequirements);
OSStatus result;
ca_require_noerr (result = mUnit.GetProperty (kAudioUnitOfflineProperty_PreflightRequirements,
kAudioUnitScope_Global, 0,
&preflightRequirements, &size), home);
// 0 indicates none, otherwise optional or required -> we do it for either
if (preflightRequirements)
{
AudioUnitRenderActionFlags renderFlags = kAudioOfflineUnitRenderAction_Preflight;
mPreflightABL->Prepare();
result = mUnit.Render (&renderFlags, &mRenderTimeStamp, 0, inNumFrames, mPreflightABL->ABL());
if (result) { printf("D result %d\n", (int)result); goto home; }
mRenderTimeStamp.mSampleTime += inNumFrames;
if (renderFlags & kAudioOfflineUnitRenderAction_Complete) {
outIsDone = true;
mRenderTimeStamp.mSampleTime = 0;
mPreflightDone = true;
mLastPercentReported = 0;
}
}
else
{
outIsDone = true;
mRenderTimeStamp.mSampleTime = 0;
mPreflightDone = true;
mLastPercentReported = 0;
}
home:
return result;
}
#endif
void SetBufferListToNumFrames (AudioBufferList &list, UInt32 inNumFrames)
{
for (unsigned int i = 0; i < list.mNumberBuffers; ++i) {
AudioBuffer &buf = list.mBuffers[i];
if (buf.mDataByteSize > 0)
buf.mDataByteSize = inNumFrames * sizeof (Float32);
}
}
OSStatus CAAUProcessor::Render (AudioBufferList *ioData,
UInt32 &ioNumFrames,
bool &outIsSilence,
bool *outOLCompleted,
bool *outOLRequiresPostProcess)
{
if (IsOfflineContext())
{
if (!mPreflightDone)
return kAudioUnitErr_InvalidOfflineRender;
// YES - this is correct!!! you have to provide both if rendering in an offline Context
*outOLCompleted = false;
*outOLRequiresPostProcess = false;
if (!IsOfflineAU() && !mUnit.Comp().Desc().IsFConv())
{
// have we processed the input we expect too?
// in an offline case, we want to create output that matches the input
// for an OfflineAU type, it manages this internally, so we don't have to do anything
// for a FormatConverter AU, we don't know and can't tell, so we can't do anything here
// for any other AU type (effect, instrument) the Prime assumption is that it will
// ask for the same number of frames of input as it is asked to output
// so we can ask what it is doing, and get a sample accurate output (which is input + tail time)
if (mRenderTimeStamp.mSampleTime + ioNumFrames >= InputSampleCount())
{
// if we fall into here, we have just a partial number of input samples left
// (less input less than what we've been asked to produce output for.
*outOLCompleted = true;
// we require post processing if we've got some tail (or latency) samples to flush through
*outOLRequiresPostProcess = mTailSamplesToProcess > 0;
if (InputSampleCount() > mRenderTimeStamp.mSampleTime) {
ioNumFrames = (UInt32)(InputSampleCount() - mRenderTimeStamp.mSampleTime);
} else {
ioNumFrames = 0;
}
mTailSamplesRemaining = mTailSamplesToProcess;
// we've got no input samples to process this time.
SetBufferListToNumFrames (*ioData, ioNumFrames);
if (ioNumFrames == 0) {
if (*outOLRequiresPostProcess)
SetInputCallback (mUnit, sSilentCallback);
else
mUnit.GlobalReset (); //flush this out, as we're done with this phase
return noErr;
}
}
}
AudioUnitRenderActionFlags renderFlags = IsOfflineAU() ? kAudioOfflineUnitRenderAction_Render : 0;
OSStatus result = mUnit.Render (&renderFlags, &mRenderTimeStamp, 0, ioNumFrames, ioData);
if (result) { printf("E result %d\n", (int)result); }
if (result) {
if (mUnit.Comp().Desc().IsFConv()) {
// this is the only way we can tell we're done with a FormatConverter AU
// - ie. client returns an error from input
result = noErr;
*outOLCompleted = true;
*outOLRequiresPostProcess = mTailSamplesToProcess > 0;
ioNumFrames = 0;
SetBufferListToNumFrames (*ioData, ioNumFrames);
} else
return result;
}
// for (UInt32 i = 0; i < ioNumFrames; ++i) {
// union {
// float f;
// unsigned char c[4];
// } u;
// u.f = ((float*)(ioData->mBuffers[0].mData))[i];
// printf("aup out %4d %14.10f %02X %02X %02X %02X\n", (int)i, u.f, u.c[0], u.c[1], u.c[2], u.c[3]);
// }
mRenderTimeStamp.mSampleTime += ioNumFrames;
outIsSilence = (renderFlags & kAudioUnitRenderAction_OutputIsSilence);
// if we're an Offline AU type, it will set this flag on completion of its processing
if (renderFlags & kAudioOfflineUnitRenderAction_Complete) {
// we now need to calculate how many frames we rendered.
// as we're dealing with PCM non-interleaved buffers, we can calculate the numFrames simply
ioNumFrames = ioData->mBuffers[0].mDataByteSize / sizeof(Float32);
*outOLCompleted = true;
*outOLRequiresPostProcess = false;
mUnit.GlobalReset (); //flush this out, as we're done with this phase
} else {
if (*outOLCompleted) {
if (*outOLRequiresPostProcess)
result = SetInputCallback (mUnit, sSilentCallback);
else
mUnit.GlobalReset (); //flush this out, as we're done with this phase
}
}
return result;
}
// rendering in a RT context:
AudioUnitRenderActionFlags renderFlags = 0;
OSStatus result = mUnit.Render (&renderFlags, &mRenderTimeStamp, 0, ioNumFrames, ioData);
if (result) { printf("F result %d\n", (int)result); }
if (!result) {
mRenderTimeStamp.mSampleTime += ioNumFrames;
outIsSilence = (renderFlags & kAudioUnitRenderAction_OutputIsSilence);
}
// for (UInt32 i = 0; i < ioNumFrames; ++i) {
// union {
// float f;
// unsigned char c[4];
// } u;
// u.f = ((float*)(ioData->mBuffers[0].mData))[i];
// printf("aup out %4d %14.10f %02X %02X %02X %02X\n", (int)i, u.f, u.c[0], u.c[1], u.c[2], u.c[3]);
// }
return result;
}
OSStatus CAAUProcessor::PostProcess (AudioBufferList *ioData,
UInt32 &ioNumFrames,
bool &outIsSilence,
bool &outDone)
{
if (IsOfflineAU() || !IsOfflineContext())
return kAudioUnitErr_CannotDoInCurrentContext;
outDone = false;
// we've got less samples to process than we've been asked to process
if (mTailSamplesRemaining <= SInt32(ioNumFrames)) {
outDone = true;
ioNumFrames = mTailSamplesRemaining > 0 ? mTailSamplesRemaining : 0;
SetBufferListToNumFrames (*ioData, ioNumFrames);
if (ioNumFrames == 0)
return noErr;
}
AudioUnitRenderActionFlags renderFlags = 0;
OSStatus result;
result = mUnit.Render (&renderFlags, &mRenderTimeStamp, 0, ioNumFrames, ioData);
if (result) { printf("G result %d\n", (int)result); goto home; }
mRenderTimeStamp.mSampleTime += ioNumFrames;
mTailSamplesRemaining -= ioNumFrames;
outIsSilence = (renderFlags & kAudioUnitRenderAction_OutputIsSilence);
if (outDone) {
ca_require_noerr (result = SetInputCallback (mUnit, mUserCallback), home);
mUnit.GlobalReset (); //flush this out, as we're done with this phase
}
home:
return result;
}
#if !TARGET_OS_IPHONE
Float32 CAAUProcessor::GetOLPercentComplete ()
{
if (!IsOfflineContext())
return 0;
Float32 percentDone = mLastPercentReported;
if (IsOfflineAU())
{
// we get the output size every time, as this can change as parameters are changed
UInt64 numOutputSamples = mNumInputSamples;
UInt32 propSize = sizeof(numOutputSamples);
mUnit.GetProperty (kAudioUnitOfflineProperty_OutputSize,
kAudioUnitScope_Global, 0, &numOutputSamples, &propSize);
percentDone = (mRenderTimeStamp.mSampleTime / Float64(numOutputSamples)) * 100.;
}
else
{
percentDone = (mRenderTimeStamp.mSampleTime / Float64(mNumInputSamples + mTailSamples)) * 100.;
}
if (percentDone > mLastPercentReported)
mLastPercentReported = percentDone;
return mLastPercentReported;
}
#endif

View File

@@ -0,0 +1,293 @@
/*
File: CAAUProcessor.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __CAAUProcessor_h__
#define __CAAUProcessor_h__
#include <AudioToolbox/AudioToolbox.h>
#include "CAStreamBasicDescription.h"
#include "CAAudioUnit.h"
#include "AUOutputBL.h"
#if TARGET_OS_IPHONE
#include <AssertMacros.h>
#endif
/*
This class wraps an AU (using the CAAudioUnit helper class) to use that AU for processing data
It can be used in a RealTime context (rendering data with RT constraints) or in an OffLine context
such as using an AU to process data that is stored in a file, and on which there are no
RT constraints to be imposed.
Order of operations:
Create an instance
Establish an Input Callback
Initialize the AU to the audio formats and whether it is going to process in an offline or RT context
Preflight
while (...)
Render // based on your calling context
PostProcess if needed (only in OL case)
After any initialization, preflighting is required.
Parameter Values on the AU should be set just before each call to Render. The sampleFrameOffsets
supplied when setting those values are an offset into that next render buffer's numFrames.
RT vs OT is determined by whether the inputSampleCount is set during Initialization, thus
this class can move the AU between RT and OL contexts. If you are using an AU of type 'auol'
(Offline), then it cannot be used in a RT context.
The CAAUProcessor will only call your Input Callback for input when it needs valid input.
This input callback will contain a sample time that indicates where within your input
you should read data from, where after preflighting, the first output data produces is for
the output sample count of zero.
MaxFrames should be set before initialisation (or is also passed in to the Reinitialize API)
If RT, then PostProcessing will *never* be required, nor will Render ever return an isDone value
If OL, then Render will at some point return isDone==true, and then also indicate if PostProcessing is required
If using a Format Converter AU in offline context, then the only way for it to determine that you've finished
is for the Input callback to return an error. This means ultimately, that you'll have potentially longer output
than you should have. The only way to manage this is for the caller to know the relationship between
input to output samples that will be required, and to call Render for just that amount of output samples
then return an error, so the tail and latency can be processed.
Tail and Latency are *only* calculated at initialisation.. Some AU's may change these properties based on
either different presets or parameter settings... Ideally, this class should listen to those properties
and recalculate its values based on those changes.
*/
class CAAUProcessor {
public:
// by default this is set to process offline
CAAUProcessor (const CAComponent& inComp);
~CAAUProcessor ();
CAAudioUnit& AU() { return mUnit; }
const CAAudioUnit& AU() const { return mUnit; }
#pragma mark __Setup APIs
bool IsOfflineContext () const { return mNumInputSamples != 0; }
// this contains the callback and client data that the AU
// uses to call when it needs input
OSStatus EstablishInputCallback (AURenderCallbackStruct &inInputCallback);
OSStatus SetAUPreset (CFPropertyListRef inPreset);
OSStatus SetAUPresetIndex (SInt32 inPresetIndex);
OSStatus SetParameter (AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
Float32 value, UInt32 bufferOffsetFrames = 0);
// a result of zero here signifies an error
UInt32 MaxFramesPerRender () const;
// this call can return an error if the AU is initialized - see Reinitialize
OSStatus SetMaxFramesPerRender (UInt32 inMaxFrames);
// Prepares the AU for processing at the specified format
// only doing n-n channel processing here.. could extend this for n-m channel processing easily enough
// if you are processing using an Offline AU, you HAVE to specify the numInputSamples to process
// if you are processing real-time, then inNumInputSamples should be zero
OSStatus Initialize (const CAStreamBasicDescription &inIODesc, UInt64 inNumInputSamples = 0)
{
return Initialize (inIODesc, inIODesc, inNumInputSamples);
}
OSStatus Initialize (const CAStreamBasicDescription &inInputDesc,
const CAStreamBasicDescription &inOutputDesc,
UInt64 inNumInputSamples = 0);
// takes the existing format state of the AU, but resets the AUProcessor so that:
// applies an optional new number of max frames
// the AUProcessor will have to be Preflighted again after this call
// Use this when you want to keep the same formats, same input sample count,
// but want to re-initialize the AU to use a new num max frames and prepare it
// appropriately...
OSStatus Reinitialize (UInt32 inNewMaxFrames);
#pragma mark __Render APIs
// Preflighting - you HAVE to preflight
// returns noErr when preflighting is done
// Offline Context:
// Offline AU's require preflighting, even if they will end up doing no work.
// In the case where the AU is offline the latency samples are trimmed and not returned
// from the consequent Render calls
// If you are NOT an offline AU then the first time Render is called,
// there will need to be some consumption of the input before you will get any valid output data.
// This is determined by the value of the AU's reported latency. So, in this case preflight
// will consume those initial samples and then return.
// Your InputCallback MUST provide the initial data that is to be processed.
// RealTime Context:
// (1 No priming. In this case inProcessPreceedingTail is false (the default) and no
// processing is done on the AU. However, because preflight is the first time that Rendering
// is called on an AU we can presume that this is outside the context of the processing that
// is occuring in the host application. To avoid taking page faults, priming cold memory, etc.
// when the AU *is* consequently used to render real data, the AU is prerolled and reset if this is the case.
// (2) Prime the AU's buffers with input data that preceeds the portion of audio you
// want to process. This amount of input data is equivalent to the tail time of the AU
// which expresses how long it takes for an sample on input to disappear from the output
// (Think of a delay or a reverb)
// So, by setting inProcessPreceedingTail to true, the preflight call will consume
// the tail time samples of input (which should be valid input BEFORE the data to be processed)
// So, your input proc here will HAVE to read samples from the preceeding input. The time
// stamps to your input proc in this case can be interpreted as 0 is the start of the preceeding data
// and you'll need to read up to the numSamples of tail time of the preceeding data.
// It discards the output results of the preflighting. If you don't have any previous data
// with which to prepare the AU, then you do NOT need to take this path and can do the step below.
// In both of these cases the inital latency frames are *not* trimmed from
// the output that will be generated by a consequent call to render.
OSStatus Preflight (bool inProcessPreceedingTail = false);
// this can be used with an OfflineAU to do a gradual preflight (so you could for instance,
// present a progress indicator. The Preflight call will do it all at once.
// If you break out of the preflight before you are done, then you HAVE to reinitialise the AU
// before you can either do another preflight or do a render, otherwise the Render call will produce
// invalid results.
OSStatus OfflineAUPreflight (UInt32 inNumFrames, bool &outIsDone);
// Here's the major stage that produces output.
// You pass in two bool flags and an ioNumFrames....
// So ioNumFrames will be *untouched* if outOLCompleted == false
// if outOLCompleted is true, ioNumFrames contains the number of valid frames within the ioData data that are valid data
// (ioData's pointers and sizes will also have been resized to match these number of frames)
// outOLRequiresPostProcess should also be checked when outOLCompleted is true,
// to see if any post-processing is required
// if rendering in a RT context, then neither outOLCompleted or outOLRequiresPostProcess is required
// if rendering in an OL context, both must be specified.
// Caller MUST provide an ABL that is set up in the previously specified output format
// If you receive kAudioUnitErr_InvalidOfflineRender when dealing with an OfflineAU Type, then you have either not
// preflighted it (and the AU requires it) or you have changed some state (its num input samples, its start offest)
// and it needs to be re-preflighted. In that case, preflight the AU again first.
OSStatus Render (AudioBufferList *ioData,
UInt32 &ioNumFrames,
bool &outIsSilence,
bool *outOLCompleted = NULL,
bool *outOLRequiresPostProcess = NULL);
// call this method if outOLRequiresPostProcess returned true upon rendering completion
OSStatus PostProcess (AudioBufferList *ioData, UInt32 &ioNumFrames, bool &outIsSilence, bool &outDone);
// This method returns how many input samples will need to be provided before
// valid output data is produced.
UInt32 LatencySampleCount () const { return mLatencySamples; }
UInt32 TailSampleCount () const { return mTailSamples; }
UInt64 InputSampleCount () const { return mNumInputSamples; }
// the class maintains the TimeStamp from render call to render call
// this value is the sample count that will be used in the *next* render call
Float64 SampleTime () const { return mRenderTimeStamp.mSampleTime; }
// in some settings (for instance a delay with 100% feedback) tail time is essentially infinite
// so you should safeguard the final OL render stage (post process) which is aimed at pulling the tail through
// default is 10 seconds
Float64 GetMaxTailTime () const { return mMaxTailTime; }
// this ONLY takes affect when you initialise the processor, it doesn't change that AU's tail time,
// but just the max amount of time that this object will allow the AU to post-process data
// set this to 0, to use the AU's tail time with no adjustment
void SetMaxTailTime (Float64 inTailTimeSecs) { mMaxTailTime = inTailTimeSecs; }
#if !TARGET_OS_IPHONE
// if this is NULL, then there is no explicit (optional or required) preflight requirement of the AU
// if this is valid, then the AU either requires or optionally requires preflighting. The default
// behaviour in this case is that the processor will preflight. This name can be used to preset
// to the user. If the AU doesn't present a name, but preflighting is optional/required, then the
// processor return "Preflight" as its string.
// the String should be released by the caller.
CFStringRef GetOLPreflightName () const;
// Returns true if this is processor is an offline AU, and that AU (whether optional or required)
// needs preflighting
bool OfflineAUNeedsPreflight () const;
// this provides a rough approximation of the progress of an Offline Processing operation (both for the
// preflight and the render phases)
Float32 GetOLPercentComplete ();
#endif
private:
CAAudioUnit mUnit;
UInt32 mLatencySamples;
UInt32 mTailSamples;
UInt32 mTailSamplesToProcess;
UInt64 mNumInputSamples;
AudioTimeStamp mRenderTimeStamp;
bool mPreflightDone;
AUOutputBL * mPreflightABL;
SInt32 mTailSamplesRemaining;
AURenderCallbackStruct mUserCallback;
Float64 mMaxTailTime;
Float32 mLastPercentReported;
bool IsOfflineAU () const { return mUnit.Comp().Desc().IsOffline(); }
void CalculateRemainderSamples (Float64 inSampleRate);
OSStatus DoInitialisation (const CAStreamBasicDescription &inInputFormat,
const CAStreamBasicDescription &inOutputFormat,
UInt64 inNumInputSamples,
UInt32 inMaxFrames);
// stop automatic copying of this object
CAAUProcessor () {}
CAAUProcessor (const CAAUProcessor &c) {}
CAAUProcessor& operator= (const CAAUProcessor& c) { return *this; }
};
#endif //__CAAUProcessor_h__

View File

@@ -0,0 +1,305 @@
/*
File: CAAtomic.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
/*
This file implements all Atomic operations using Interlocked functions specified in
Winbase.h
NOTE: According to Microsoft documentation, all Interlocked functions generates a
full barrier.
On Windows:
As the Interlocked functions returns the Old value, Extra checks and operations
are made after the atomic operation to return value consistent with OSX counterparts.
*/
#ifndef __CAAtomic_h__
#define __CAAtomic_h__
#if TARGET_OS_WIN32
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(_InterlockedOr)
#pragma intrinsic(_InterlockedAnd)
#else
#include <CoreFoundation/CFBase.h>
#include <libkern/OSAtomic.h>
#endif
inline void CAMemoryBarrier()
{
#if TARGET_OS_WIN32
MemoryBarrier();
#else
OSMemoryBarrier();
#endif
}
inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue)
{
#if TARGET_OS_WIN32
long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt);
// InterlockedExchangeAdd returns the original value which differs from OSX version.
// At this point the addition would have occured and hence returning the new value
// to keep it sync with OSX.
return lRetVal + theAmt;
#else
return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue);
#endif
}
inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue)
{
#if TARGET_OS_WIN32
// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
// function instead.
long j = _InterlockedOr((volatile long*)theValue, theMask);
// _InterlockedOr returns the original value which differs from OSX version.
// Returning the new value similar to OSX
return (SInt32)(j | theMask);
#else
return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue);
#endif
}
inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue)
{
#if TARGET_OS_WIN32
// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
// function instead.
long j = _InterlockedAnd((volatile long*)theValue, theMask);
// _InterlockedAnd returns the original value which differs from OSX version.
// Returning the new value similar to OSX
return (SInt32)(j & theMask);
#else
return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue);
#endif
}
inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue)
{
#if TARGET_OS_WIN32
// InterlockedCompareExchange returns the old value. But we need to return bool value.
long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue);
// Hence we check if the new value is set and if it is we return true else false.
// If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen.
return (oldValue == lRetVal);
#else
return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue);
#endif
}
inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue)
{
#if TARGET_OS_WIN32
return (SInt32)InterlockedIncrement((volatile long*)theValue);
#else
return OSAtomicIncrement32((volatile int32_t *)theValue);
#endif
}
inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue)
{
#if TARGET_OS_WIN32
return (SInt32)InterlockedDecrement((volatile long*)theValue);
#else
return OSAtomicDecrement32((volatile int32_t *)theValue);
#endif
}
inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue)
{
#if TARGET_OS_WIN32
return CAAtomicIncrement32(theValue);
#else
return OSAtomicIncrement32Barrier((volatile int32_t *)theValue);
#endif
}
inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue)
{
#if TARGET_OS_WIN32
return CAAtomicDecrement32(theValue);
#else
return OSAtomicDecrement32Barrier((volatile int32_t *)theValue);
#endif
}
inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress)
{
#if TARGET_OS_WIN32
BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear);
return (bOldVal ? true : false);
#else
return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress);
#endif
}
inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress)
{
#if TARGET_OS_WIN32
BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress);
return (bOldVal ? true : false);
#else
return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress);
#endif
}
inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress)
{
#if TARGET_OS_WIN32
BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet);
return (bOldVal ? true : false);
#else
return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress);
#endif
}
// int32_t flavors -- for C++ only since we can't overload in C
// CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then
// this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where
// SInt32 is defined as signed long so this would work there.
// So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included.
#if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__
inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue)
{
return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue);
}
inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue)
{
return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue);
}
inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue)
{
return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue);
}
inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue)
{
return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue);
}
inline int32_t CAAtomicIncrement32(volatile int32_t* theValue)
{
return CAAtomicIncrement32((volatile SInt32 *)theValue);
}
inline int32_t CAAtomicDecrement32(volatile int32_t* theValue)
{
return CAAtomicDecrement32((volatile SInt32 *)theValue);
}
inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue)
{
return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue);
}
inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue)
{
return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue);
}
#endif // __cplusplus && !__LP64__
#if __LP64__
inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue )
{
return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue);
}
#endif
inline bool CAAtomicCompareAndSwapPtrBarrier(void *__oldValue, void *__newValue, volatile void ** __theValue)
{
#if __LP64__
return CAAtomicCompareAndSwap64Barrier((int64_t)__oldValue, (int64_t)__newValue, (int64_t *)__theValue);
#else
return CAAtomicCompareAndSwap32Barrier((int32_t)__oldValue, (int32_t)__newValue, (int32_t *)__theValue);
#endif
}
/* Spinlocks. These use memory barriers as required to synchronize access to shared
* memory protected by the lock. The lock operation spins, but employs various strategies
* to back off if the lock is held, making it immune to most priority-inversion livelocks.
* The try operation immediately returns false if the lock was held, true if it took the
* lock. The convention is that unlocked is zero, locked is nonzero.
*/
#define CA_SPINLOCK_INIT 0
typedef int32_t CASpinLock;
bool CASpinLockTry( volatile CASpinLock *__lock );
void CASpinLockLock( volatile CASpinLock *__lock );
void CASpinLockUnlock( volatile CASpinLock *__lock );
inline void CASpinLockLock( volatile CASpinLock *__lock )
{
#if TARGET_OS_MAC
OSSpinLockLock(__lock);
#else
while (CAAtomicTestAndSetBarrier(0, (void*)__lock))
usleep(1000); // ???
#endif
}
inline void CASpinLockUnlock( volatile CASpinLock *__lock )
{
#if TARGET_OS_MAC
OSSpinLockUnlock(__lock);
#else
CAAtomicTestAndClearBarrier(0, (void*)__lock);
#endif
}
inline bool CASpinLockTry( volatile CASpinLock *__lock )
{
#if TARGET_OS_MAC
return OSSpinLockTry(__lock);
#else
return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0);
#endif
}
#endif // __CAAtomic_h__

View File

@@ -0,0 +1,239 @@
/*
File: CAAtomicStack.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#ifndef __CAAtomicStack_h__
#define __CAAtomicStack_h__
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <libkern/OSAtomic.h>
#else
#include <CAAtomic.h>
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
#include <CoreServices/CoreServices.h>
#endif
// linked list LIFO or FIFO (pop_all_reversed) stack, elements are pushed and popped atomically
// class T must implement T *& next().
template <class T>
class TAtomicStack {
public:
TAtomicStack() : mHead(NULL) { }
// non-atomic routines, for use when initializing/deinitializing, operate NON-atomically
void push_NA(T *item)
{
item->next() = mHead;
mHead = item;
}
T * pop_NA()
{
T *result = mHead;
if (result)
mHead = result->next();
return result;
}
bool empty() const { return mHead == NULL; }
T * head() { return mHead; }
// atomic routines
void push_atomic(T *item)
{
T *head_;
do {
head_ = mHead;
item->next() = head_;
} while (!compare_and_swap(head_, item, &mHead));
}
void push_multiple_atomic(T *item)
// pushes entire linked list headed by item
{
T *head_, *p = item, *tail;
// find the last one -- when done, it will be linked to head
do {
tail = p;
p = p->next();
} while (p);
do {
head_ = mHead;
tail->next() = head_;
} while (!compare_and_swap(head_, item, &mHead));
}
T * pop_atomic_single_reader()
// this may only be used when only one thread may potentially pop from the stack.
// if multiple threads may pop, this suffers from the ABA problem.
// <rdar://problem/4606346> TAtomicStack suffers from the ABA problem
{
T *result;
do {
if ((result = mHead) == NULL)
break;
} while (!compare_and_swap(result, result->next(), &mHead));
return result;
}
T * pop_atomic()
// This is inefficient for large linked lists.
// prefer pop_all() to a series of calls to pop_atomic.
// push_multiple_atomic has to traverse the entire list.
{
T *result = pop_all();
if (result) {
T *next = result->next();
if (next)
// push all the remaining items back onto the stack
push_multiple_atomic(next);
}
return result;
}
T * pop_all()
{
T *result;
do {
if ((result = mHead) == NULL)
break;
} while (!compare_and_swap(result, NULL, &mHead));
return result;
}
T* pop_all_reversed()
{
TAtomicStack<T> reversed;
T *p = pop_all(), *next;
while (p != NULL) {
next = p->next();
reversed.push_NA(p);
p = next;
}
return reversed.mHead;
}
static bool compare_and_swap(T *oldvalue, T *newvalue, T **pvalue)
{
#if TARGET_OS_MAC
#if __LP64__
return ::OSAtomicCompareAndSwap64Barrier(int64_t(oldvalue), int64_t(newvalue), (int64_t *)pvalue);
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
return ::OSAtomicCompareAndSwap32Barrier(int32_t(oldvalue), int32_t(newvalue), (int32_t *)pvalue);
#else
return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
#endif
#else
//return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
return CAAtomicCompareAndSwap32Barrier(SInt32(oldvalue), SInt32(newvalue), (SInt32*)pvalue);
#endif
}
protected:
T * mHead;
};
#if ((MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) && !TARGET_OS_WIN32)
#include <libkern/OSAtomic.h>
class CAAtomicStack {
public:
CAAtomicStack(size_t nextPtrOffset) : mNextPtrOffset(nextPtrOffset) {
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
mHead.opaque1 = 0; mHead.opaque2 = 0;
}
// a subset of the above
void push_atomic(void *p) { OSAtomicEnqueue(&mHead, p, mNextPtrOffset); }
void push_NA(void *p) { push_atomic(p); }
void * pop_atomic() { return OSAtomicDequeue(&mHead, mNextPtrOffset); }
void * pop_atomic_single_reader() { return pop_atomic(); }
void * pop_NA() { return pop_atomic(); }
private:
OSQueueHead mHead;
size_t mNextPtrOffset;
};
// a more efficient subset of TAtomicStack using OSQueue.
template <class T>
class TAtomicStack2 {
public:
TAtomicStack2() {
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
mHead.opaque1 = 0; mHead.opaque2 = 0;
mNextPtrOffset = -1;
}
void push_atomic(T *item) {
if (mNextPtrOffset < 0) {
T **pnext = &item->next(); // hack around offsetof not working with C++
mNextPtrOffset = (Byte *)pnext - (Byte *)item;
}
OSAtomicEnqueue(&mHead, item, mNextPtrOffset);
}
void push_NA(T *item) { push_atomic(item); }
T * pop_atomic() { return (T *)OSAtomicDequeue(&mHead, mNextPtrOffset); }
T * pop_atomic_single_reader() { return pop_atomic(); }
T * pop_NA() { return pop_atomic(); }
// caution: do not try to implement pop_all_reversed here. the writer could add new elements
// while the reader is trying to pop old ones!
private:
OSQueueHead mHead;
ssize_t mNextPtrOffset;
};
#else
#define TAtomicStack2 TAtomicStack
#endif // MAC_OS_X_VERSION_MAX_ALLOWED && !TARGET_OS_WIN32
#endif // __CAAtomicStack_h__

View File

@@ -0,0 +1,239 @@
/*
File: CAAudioBufferList.cpp
Abstract: CAAudioBufferList.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
//=============================================================================
// Includes
//=============================================================================
#include "CAAudioBufferList.h"
#include "CADebugMacros.h"
#include "CALogMacros.h"
#include <stdlib.h>
#include <string.h>
//=============================================================================
// CAAudioBufferList
//=============================================================================
AudioBufferList* CAAudioBufferList::Create(UInt32 inNumberBuffers)
{
UInt32 theSize = CalculateByteSize(inNumberBuffers);
AudioBufferList* theAnswer = static_cast<AudioBufferList*>(calloc(1, theSize));
if(theAnswer != NULL)
{
theAnswer->mNumberBuffers = inNumberBuffers;
}
return theAnswer;
}
void CAAudioBufferList::Destroy(AudioBufferList* inBufferList)
{
free(inBufferList);
}
UInt32 CAAudioBufferList::CalculateByteSize(UInt32 inNumberBuffers)
{
UInt32 theSize = SizeOf32(AudioBufferList) - SizeOf32(AudioBuffer);
theSize += inNumberBuffers * SizeOf32(AudioBuffer);
return theSize;
}
UInt32 CAAudioBufferList::GetTotalNumberChannels(const AudioBufferList& inBufferList)
{
UInt32 theAnswer = 0;
for(UInt32 theIndex = 0; theIndex < inBufferList.mNumberBuffers; ++theIndex)
{
theAnswer += inBufferList.mBuffers[theIndex].mNumberChannels;
}
return theAnswer;
}
bool CAAudioBufferList::GetBufferForChannel(const AudioBufferList& inBufferList, UInt32 inChannel, UInt32& outBufferNumber, UInt32& outBufferChannel)
{
bool theAnswer = false;
UInt32 theIndex = 0;
while((theIndex < inBufferList.mNumberBuffers) && (inChannel >= inBufferList.mBuffers[theIndex].mNumberChannels))
{
inChannel -= inBufferList.mBuffers[theIndex].mNumberChannels;
++theIndex;
}
if(theIndex < inBufferList.mNumberBuffers)
{
outBufferNumber = theIndex;
outBufferChannel = inChannel;
theAnswer = true;
}
return theAnswer;
}
void CAAudioBufferList::Clear(AudioBufferList& outBufferList)
{
// assumes that "0" is actually the 0 value for this stream format
for(UInt32 theBufferIndex = 0; theBufferIndex < outBufferList.mNumberBuffers; ++theBufferIndex)
{
if(outBufferList.mBuffers[theBufferIndex].mData != NULL)
{
memset(outBufferList.mBuffers[theBufferIndex].mData, 0, outBufferList.mBuffers[theBufferIndex].mDataByteSize);
}
}
}
void CAAudioBufferList::Copy(const AudioBufferList& inSource, UInt32 inStartingSourceChannel, AudioBufferList& outDestination, UInt32 inStartingDestinationChannel)
{
// This is a brute force copy method that can handle ABL's that have different buffer layouts
// This means that this method is probably not the fastest way to do this for all cases.
// This method also assumes that both the source and destination sample formats are Float32
UInt32 theInputChannel = inStartingSourceChannel;
UInt32 theNumberInputChannels = GetTotalNumberChannels(inSource);
UInt32 theOutputChannel = inStartingDestinationChannel;
UInt32 theNumberOutputChannels = GetTotalNumberChannels(outDestination);
UInt32 theInputBufferIndex = 0;
UInt32 theInputBufferChannel = 0;
UInt32 theOutputBufferIndex = 0;
UInt32 theOutputBufferChannel = 0;
while((theInputChannel < theNumberInputChannels) && (theOutputChannel < theNumberOutputChannels))
{
GetBufferForChannel(inSource, theInputChannel, theInputBufferIndex, theInputBufferChannel);
GetBufferForChannel(inSource, theOutputChannel, theOutputBufferIndex, theOutputBufferChannel);
CopyChannel(inSource.mBuffers[theInputBufferIndex], theInputBufferChannel, outDestination.mBuffers[theOutputBufferIndex], theOutputBufferChannel);
++theInputChannel;
++theOutputChannel;
}
}
void CAAudioBufferList::CopyChannel(const AudioBuffer& inSource, UInt32 inSourceChannel, AudioBuffer& outDestination, UInt32 inDestinationChannel)
{
// set up the stuff for the loop
UInt32 theNumberFramesToCopy = outDestination.mDataByteSize / (outDestination.mNumberChannels * SizeOf32(Float32));
const Float32* theSource = static_cast<const Float32*>(inSource.mData);
Float32* theDestination = static_cast<Float32*>(outDestination.mData);
// loop through the data and copy the samples
while(theNumberFramesToCopy > 0)
{
// copy the data
theDestination[inDestinationChannel] = theSource[inSourceChannel];
// adjust the pointers
--theNumberFramesToCopy;
theSource += inSource.mNumberChannels;
theDestination += outDestination.mNumberChannels;
}
}
void CAAudioBufferList::Sum(const AudioBufferList& inSourceBufferList, AudioBufferList& ioSummedBufferList)
{
// assumes that the buffers are Float32 samples and the listst have the same layout
// this is a lame algorithm, by the way. it could at least be unrolled a couple of times
for(UInt32 theBufferIndex = 0; theBufferIndex < ioSummedBufferList.mNumberBuffers; ++theBufferIndex)
{
Float32* theSourceBuffer = static_cast<Float32*>(inSourceBufferList.mBuffers[theBufferIndex].mData);
Float32* theSummedBuffer = static_cast<Float32*>(ioSummedBufferList.mBuffers[theBufferIndex].mData);
UInt32 theNumberSamplesToMix = ioSummedBufferList.mBuffers[theBufferIndex].mDataByteSize / SizeOf32(Float32);
if((theSourceBuffer != NULL) && (theSummedBuffer != NULL) && (theNumberSamplesToMix > 0))
{
while(theNumberSamplesToMix > 0)
{
*theSummedBuffer += *theSourceBuffer;
++theSummedBuffer;
++theSourceBuffer;
--theNumberSamplesToMix;
}
}
}
}
bool CAAudioBufferList::HasData(AudioBufferList& inBufferList)
{
bool hasData = false;
for(UInt32 theBufferIndex = 0; !hasData && (theBufferIndex < inBufferList.mNumberBuffers); ++theBufferIndex)
{
if(inBufferList.mBuffers[theBufferIndex].mData != NULL)
{
UInt32* theBuffer = (UInt32*)inBufferList.mBuffers[theBufferIndex].mData;
UInt32 theNumberSamples = inBufferList.mBuffers[theBufferIndex].mDataByteSize / SizeOf32(UInt32);
for(UInt32 theSampleIndex = 0; !hasData && (theSampleIndex < theNumberSamples); ++theSampleIndex)
{
hasData = theBuffer[theSampleIndex] != 0;
}
}
}
return hasData;
}
#if CoreAudio_Debug
void CAAudioBufferList::PrintToLog(const AudioBufferList& inBufferList)
{
PrintInt(" Number streams: ", inBufferList.mNumberBuffers);
for(UInt32 theIndex = 0; theIndex < inBufferList.mNumberBuffers; ++theIndex)
{
PrintIndexedInt(" Channels in stream", theIndex + 1, inBufferList.mBuffers[theIndex].mNumberChannels);
PrintIndexedInt(" Buffer size of stream", theIndex + 1, inBufferList.mBuffers[theIndex].mDataByteSize);
}
}
#endif
const AudioBufferList* CAAudioBufferList::GetEmptyBufferList()
{
static bool sInitializer = false;
static AudioBufferList sEmptyABL;
if(!sInitializer)
{
memset(&sEmptyABL, 0, sizeof(AudioBufferList));
}
return &sEmptyABL;
}

View File

@@ -0,0 +1,108 @@
/*
File: CAAudioBufferList.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__CAAudioBufferList_h__)
#define __CAAudioBufferList_h__
//=============================================================================
// Includes
//=============================================================================
// System Includes
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreAudio/CoreAudioTypes.h>
#else
#include <CoreAudioTypes.h>
#endif
#include "CAException.h"
#include "CADebugMacros.h"
//=============================================================================
// Types
//=============================================================================
typedef AudioBufferList* AudioBufferListPtr;
//=============================================================================
// CAAudioBufferList
//=============================================================================
struct CAAudioBufferList
{
// Construction/Destruction
public:
static AudioBufferList* Create(UInt32 inNumberBuffers);
static void Destroy(AudioBufferList* inBufferList);
static UInt32 CalculateByteSize(UInt32 inNumberBuffers);
// Operations
public:
static UInt32 GetTotalNumberChannels(const AudioBufferList& inBufferList);
static bool GetBufferForChannel(const AudioBufferList& inBufferList, UInt32 inChannel, UInt32& outBufferNumber, UInt32& outBufferChannel);
static void Clear(AudioBufferList& outBufferList);
static void Copy(const AudioBufferList& inSource, UInt32 inStartingSourceChannel, AudioBufferList& outDestination, UInt32 inStartingDestinationChannel);
static void CopyChannel(const AudioBuffer& inSource, UInt32 inSourceChannel, AudioBuffer& outDestination, UInt32 inDestinationChannel);
static void Sum(const AudioBufferList& inSourceBufferList, AudioBufferList& ioSummedBufferList);
static bool HasData(AudioBufferList& inBufferList);
#if CoreAudio_Debug
static void PrintToLog(const AudioBufferList& inBufferList);
#endif
static const AudioBufferList* GetEmptyBufferList();
};
// Declare a variably-sized AudioBufferList on the stack
#define STACK_ABL(name, nbufs) \
ThrowIf(nbufs < 1 || nbufs > 64, CAException(kAudio_ParamError), "STACK_ABL: invalid number of buffers") \
const size_t name##_ByteSize = sizeof(AudioBufferList) + (nbufs - 1) * sizeof(AudioBuffer); \
AudioBufferList &name = *(AudioBufferList *)alloca(name##_ByteSize); \
name.mNumberBuffers = nbufs;
#endif

View File

@@ -0,0 +1,153 @@
/*
File: CAAudioChannelLayout.cpp
Abstract: CAAudioChannelLayout.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
//=============================================================================
// Includes
//=============================================================================
// Self Include
#include "CAAudioChannelLayout.h"
#include "CAAutoDisposer.h"
#include <stdlib.h>
#include <string.h>
//=============================================================================
// CAAudioChannelLayout
//=============================================================================
AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions)
{
UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions);
AudioChannelLayout* theAnswer = static_cast<AudioChannelLayout*>(CA_calloc(1, theSize));
if(theAnswer != NULL)
{
SetAllToUnknown(*theAnswer, inNumberChannelDescriptions);
}
return theAnswer;
}
void CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout)
{
free(inChannelLayout);
}
void CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions)
{
outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
outChannelLayout.mChannelBitmap = 0;
outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions;
for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex)
{
outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown;
outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0;
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0;
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0;
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0;
}
}
bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y)
{
// compare based on the number of channel descriptions present
// (this may be too strict a comparison if all you care about are matching layout tags)
UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions);
UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions);
if (theSize1 != theSize2)
return false;
return !memcmp (&x, &y, theSize1);
}
bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y)
{
return !(x == y);
}
// counting the one bits in a word
inline UInt32 CountOnes(UInt32 x)
{
// secret magic algorithm for counting bits in a word.
UInt32 t;
x = x - ((x >> 1) & 0x55555555);
t = ((x >> 2) & 0x33333333);
x = (x & 0x33333333) + t;
x = (x + (x >> 4)) & 0x0F0F0F0F;
x = x + (x << 8);
x = x + (x << 16);
return x >> 24;
}
UInt32 CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout)
{
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
return inLayout.mNumberChannelDescriptions;
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
return CountOnes (inLayout.mChannelBitmap);
return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag);
}
void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout)
{
if (layout == NULL)
{
fprintf (file, "\tNULL layout\n");
return;
}
fprintf (file, "\tTag=0x%X, ", (int)layout->mChannelLayoutTag);
if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
fprintf (file, "Using Bitmap:0x%X\n", (int)layout->mChannelBitmap);
else {
fprintf (file, "Num Chan Descs=%d\n", (int)layout->mNumberChannelDescriptions);
const AudioChannelDescription *desc = layout->mChannelDescriptions;
for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) {
fprintf (file, "\t\tLabel=%d, Flags=0x%X, ", (int)desc->mChannelLabel, (int)desc->mChannelFlags);
fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]);
}
}
}

View File

@@ -0,0 +1,199 @@
/*
File: CAAudioChannelLayout.h
Abstract: Part of CoreAudio Utility Classes
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#if !defined(__CAAudioChannelLayout_h__)
#define __CAAudioChannelLayout_h__
//=============================================================================
// Includes
//=============================================================================
// System Includes
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreAudio/CoreAudioTypes.h>
#include <CoreFoundation/CoreFoundation.h>
#else
#include <CoreAudioTypes.h>
#include <CoreFoundation.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CADebugMacros.h"
#include "CAAutoDisposer.h"
#if !HAL_Build
#include "CAReferenceCounted.h"
#endif
//=============================================================================
// CAAudioChannelLayout
//=============================================================================
bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y);
bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y);
extern "C" void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout);
class CAAudioChannelLayout
{
// static Construction/Destruction
public:
static AudioChannelLayout* Create(UInt32 inNumberChannelDescriptions);
static void Destroy(AudioChannelLayout* inChannelLayout);
static UInt32 CalculateByteSize(UInt32 inNumberChannelDescriptions) {
return SizeOf32(AudioChannelLayout) - SizeOf32(AudioChannelDescription) + (inNumberChannelDescriptions * SizeOf32(AudioChannelDescription));
}
static void SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions);
static UInt32 NumberChannels(const AudioChannelLayout& inLayout);
#if !HAL_Build
// object methods
public:
CAAudioChannelLayout ();
CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
// if inChooseSurround is false, then symmetrical speaker arrangements
// are chosen in place of surround layouts if there is a choice
// This call chooses layouts based on the expected defaults in
// AudioUnit usage
CAAudioChannelLayout (AudioChannelLayoutTag inTag);
CAAudioChannelLayout (const CAAudioChannelLayout &c);
CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout);
~CAAudioChannelLayout();
CAAudioChannelLayout& operator= (const AudioChannelLayout* inChannelLayout);
CAAudioChannelLayout& operator= (const CAAudioChannelLayout& c);
bool operator== (const CAAudioChannelLayout &c) const;
bool operator!= (const CAAudioChannelLayout &c) const;
void SetWithTag(AudioChannelLayoutTag inTag);
bool IsValid() const { return NumberChannels() > 0; }
UInt32 Size() const { return mLayout ? mLayout->Size() : 0; }
UInt32 NumberChannels() const { return mLayout ? mLayout->NumberChannels() : 0; }
AudioChannelLayoutTag Tag() const { return Layout().mChannelLayoutTag; }
const AudioChannelLayout& Layout() const { return mLayout->Layout(); }
operator const AudioChannelLayout *() const { return &Layout(); }
void Print () const { Print (stdout); }
void Print (FILE* file) const;
OSStatus Save (CFPropertyListRef *outData) const;
OSStatus Restore (CFPropertyListRef &inData);
private:
class RefCountedLayout : public CAReferenceCounted {
void * operator new(size_t /* size */, size_t aclSize)
{
return CA_malloc(sizeof(RefCountedLayout) - sizeof(AudioChannelLayout) + aclSize);
}
void operator delete(void *mem)
{
free(mem);
}
RefCountedLayout(UInt32 inDataSize) :
mByteSize(inDataSize)
{
memset(&mACL, 0, inDataSize);
}
public:
static RefCountedLayout *CreateWithNumberChannelDescriptions(unsigned nChannels) {
size_t size = CAAudioChannelLayout::CalculateByteSize(nChannels);
return new(size) RefCountedLayout((UInt32)size);
}
static RefCountedLayout *CreateWithLayout(const AudioChannelLayout *layout) {
size_t size = CAAudioChannelLayout::CalculateByteSize(layout->mNumberChannelDescriptions);
RefCountedLayout *acl = new(size) RefCountedLayout((UInt32)size);
memcpy(&acl->mACL, layout, size);
return acl;
}
static RefCountedLayout *CreateWithLayoutTag(AudioChannelLayoutTag layoutTag) {
RefCountedLayout *acl = CreateWithNumberChannelDescriptions(0);
acl->mACL.mChannelLayoutTag = layoutTag;
return acl;
}
const AudioChannelLayout & Layout() const { return mACL; }
UInt32 Size () const { return mByteSize; }
UInt32 NumberChannels() { return CAAudioChannelLayout::NumberChannels(Layout()); }
private:
const UInt32 mByteSize;
AudioChannelLayout mACL;
// * * * mACL is variable length and thus must be last * * *
// only the constructors can change the actual state of the layout
friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData);
friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout);
friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag);
AudioChannelLayout * GetLayout() { return &mACL; }
private:
// prohibited methods: private and unimplemented.
RefCountedLayout();
RefCountedLayout(const RefCountedLayout& c);
RefCountedLayout& operator=(const RefCountedLayout& c);
};
RefCountedLayout *mLayout;
#endif // HAL_Build
};
#endif

View File

@@ -0,0 +1,210 @@
/*
File: CAAudioChannelLayoutObject.cpp
Abstract: CAAudioChannelLayoutObject.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CAAudioChannelLayout.h"
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <AudioToolbox/AudioFormat.h>
#else
#include <AudioFormat.h>
#endif
CAAudioChannelLayout::CAAudioChannelLayout ()
{
mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(0);
}
//=============================================================================
// CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround)
{
// this chooses default layouts based on the number of channels...
AudioChannelLayoutTag tag;
switch (inNumberChannels)
{
default:
// here we have a "broken" layout, in the sense that we haven't any idea how to lay this out
mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(inNumberChannels);
SetAllToUnknown(*mLayout->GetLayout(), inNumberChannels);
return; // don't fall into the tag case
case 1:
tag = kAudioChannelLayoutTag_Mono;
break;
case 2:
tag = inChooseSurround ? kAudioChannelLayoutTag_Binaural : kAudioChannelLayoutTag_Stereo;
break;
case 4:
tag = inChooseSurround ? kAudioChannelLayoutTag_Ambisonic_B_Format : kAudioChannelLayoutTag_AudioUnit_4;
break;
case 5:
tag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_5_0 : kAudioChannelLayoutTag_AudioUnit_5;
break;
case 6:
tag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_6_0 : kAudioChannelLayoutTag_AudioUnit_6;
break;
case 7:
tag = kAudioChannelLayoutTag_AudioUnit_7_0;
break;
case 8:
tag = kAudioChannelLayoutTag_AudioUnit_8;
break;
}
mLayout = RefCountedLayout::CreateWithLayoutTag(tag);
}
//=============================================================================
// CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (AudioChannelLayoutTag inLayoutTag)
: mLayout(NULL)
{
SetWithTag(inLayoutTag);
}
//=============================================================================
// CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (const CAAudioChannelLayout &c)
: mLayout(NULL)
{
*this = c;
}
//=============================================================================
// CAAudioChannelLayout::AudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout)
: mLayout(NULL)
{
*this = inChannelLayout;
}
//=============================================================================
// CAAudioChannelLayout::~CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::~CAAudioChannelLayout ()
{
if (mLayout) {
mLayout->release();
mLayout = NULL;
}
}
//=============================================================================
// CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout& CAAudioChannelLayout::operator= (const CAAudioChannelLayout &c)
{
if (mLayout != c.mLayout) {
if (mLayout)
mLayout->release();
if ((mLayout = c.mLayout) != NULL)
mLayout->retain();
}
return *this;
}
CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout)
{
if (mLayout && &mLayout->Layout() == inChannelLayout)
return *this;
if (mLayout)
mLayout->release();
if (inChannelLayout == NULL)
{
mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(0);
}
else
{
mLayout = RefCountedLayout::CreateWithLayout(inChannelLayout);
}
return *this;
}
void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag)
{
if (mLayout)
mLayout->release();
mLayout = RefCountedLayout::CreateWithLayoutTag(inTag);
}
//=============================================================================
// CAAudioChannelLayout::operator==
//=============================================================================
bool CAAudioChannelLayout::operator== (const CAAudioChannelLayout &c) const
{
if (mLayout == c.mLayout)
return true;
return Layout() == c.Layout();
}
//=============================================================================
// CAAudioChannelLayout::operator!=
//=============================================================================
bool CAAudioChannelLayout::operator!= (const CAAudioChannelLayout &c) const
{
if (mLayout == c.mLayout)
return false;
return !(Layout() == c.Layout());
}
//=============================================================================
// CAAudioChannelLayout::Print
//=============================================================================
void CAAudioChannelLayout::Print (FILE* file) const
{
CAShowAudioChannelLayout (file, &Layout());
}

View File

@@ -0,0 +1,424 @@
/*
File: CAAudioFileFormats.cpp
Abstract: CAAudioFileFormats.h
Version: 1.1
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) 2014 Apple Inc. All Rights Reserved.
*/
#include "CAAudioFileFormats.h"
#include <algorithm>
#include <ctype.h>
CAAudioFileFormats *CAAudioFileFormats::sInstance = NULL;
CAAudioFileFormats *CAAudioFileFormats::Instance(bool loadDataFormats)
{
if (sInstance == NULL)
sInstance = new CAAudioFileFormats(loadDataFormats);
return sInstance;
}
/*
class CompareFileFormatNames {
public:
bool operator() (const CAAudioFileFormats::FileFormatInfo &a, const CAAudioFileFormats::FileFormatInfo &b)
{
return CFStringCompare(a.mFileTypeName, b.mFileTypeName,
kCFCompareCaseInsensitive | kCFCompareLocalized) == kCFCompareLessThan;
}
};*/
static int CompareFileFormatNames(const void *va, const void *vb)
{
CAAudioFileFormats::FileFormatInfo *a = (CAAudioFileFormats::FileFormatInfo *)va,
*b = (CAAudioFileFormats::FileFormatInfo *)vb;
return CFStringCompare(a->mFileTypeName, b->mFileTypeName,
kCFCompareCaseInsensitive | kCFCompareLocalized);
}
CAAudioFileFormats::CAAudioFileFormats(bool loadDataFormats) :
mNumFileFormats(0), mFileFormats(NULL)
{
OSStatus err;
UInt32 size;
UInt32 *fileTypes = NULL;
// get all file types
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size);
if (err != noErr) goto bail;
mNumFileFormats = size / sizeof(UInt32);
mFileFormats = new FileFormatInfo[mNumFileFormats];
fileTypes = new UInt32[mNumFileFormats];
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size, fileTypes);
if (err != noErr) goto bail;
// get info for each file type
for (int i = 0; i < mNumFileFormats; ++i) {
FileFormatInfo *ffi = &mFileFormats[i];
OSType filetype = fileTypes[i];
ffi->mFileTypeID = filetype;
// file type name
ffi->mFileTypeName = NULL;
size = sizeof(CFStringRef);
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_FileTypeName, sizeof(UInt32), &filetype, &size, &ffi->mFileTypeName);
if (err == noErr && ffi->mFileTypeName)
CFRetain(ffi->mFileTypeName);
// file extensions
size = sizeof(CFArrayRef);
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_ExtensionsForType,
sizeof(OSType), &filetype, &size, &ffi->mExtensions);
if (err)
ffi->mExtensions = NULL;
// file data formats
ffi->mNumDataFormats = 0;
ffi->mDataFormats = NULL;
if (loadDataFormats)
ffi->LoadDataFormats();
}
// sort file formats by name
qsort(mFileFormats, mNumFileFormats, sizeof(FileFormatInfo), CompareFileFormatNames);
bail:
delete[] fileTypes;
}
void CAAudioFileFormats::FileFormatInfo::LoadDataFormats()
{
if (mDataFormats != NULL) return;
UInt32 *writableFormats = NULL, *readableFormats = NULL;
int nWritableFormats, nReadableFormats;
// get all writable formats
UInt32 size;
OSStatus err = AudioFormatGetPropertyInfo(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size);
if (err != noErr) goto bail;
nWritableFormats = size / sizeof(UInt32);
writableFormats = new UInt32[nWritableFormats];
err = AudioFormatGetProperty(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size, writableFormats);
if (err != noErr) goto bail;
// get all readable formats
err = AudioFormatGetPropertyInfo(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size);
if (err != noErr) goto bail;
nReadableFormats = size / sizeof(UInt32);
readableFormats = new UInt32[nReadableFormats];
err = AudioFormatGetProperty(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size, readableFormats);
if (err != noErr) goto bail;
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableFormatIDs, sizeof(UInt32), &mFileTypeID, &size);
if (err == noErr) {
mNumDataFormats = size / sizeof(OSType);
OSType *formatIDs = new OSType[mNumDataFormats];
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableFormatIDs,
sizeof(UInt32), &mFileTypeID, &size, formatIDs);
if (err == noErr) {
mDataFormats = new DataFormatInfo[mNumDataFormats];
for (int j = 0; j < mNumDataFormats; ++j) {
int k;
bool anyBigEndian = false, anyLittleEndian = false;
DataFormatInfo *dfi = &mDataFormats[j];
dfi->mFormatID = formatIDs[j];
dfi->mReadable = (dfi->mFormatID == kAudioFormatLinearPCM);
dfi->mWritable = (dfi->mFormatID == kAudioFormatLinearPCM);
for (k = 0; k < nReadableFormats; ++k)
if (readableFormats[k] == dfi->mFormatID) {
dfi->mReadable = true;
break;
}
for (k = 0; k < nWritableFormats; ++k)
if (writableFormats[k] == dfi->mFormatID) {
dfi->mWritable = true;
break;
}
dfi->mNumVariants = 0;
AudioFileTypeAndFormatID tf = { mFileTypeID, dfi->mFormatID };
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat,
sizeof(AudioFileTypeAndFormatID), &tf, &size);
if (err == noErr) {
dfi->mNumVariants = size / sizeof(AudioStreamBasicDescription);
dfi->mVariants = new AudioStreamBasicDescription[dfi->mNumVariants];
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat,
sizeof(AudioFileTypeAndFormatID), &tf, &size, dfi->mVariants);
if (err) {
dfi->mNumVariants = 0;
delete[] dfi->mVariants;
dfi->mVariants = NULL;
} else {
for (k = 0; k < dfi->mNumVariants; ++k) {
AudioStreamBasicDescription *desc = &dfi->mVariants[k];
if (desc->mBitsPerChannel > 8) {
if (desc->mFormatFlags & kAudioFormatFlagIsBigEndian)
anyBigEndian = true;
else
anyLittleEndian = true;
}
}
}
}
dfi->mEitherEndianPCM = (anyBigEndian && anyLittleEndian);
}
}
delete[] formatIDs;
}
bail:
delete[] readableFormats;
delete[] writableFormats;
}
// note that the outgoing format will have zero for the sample rate, channels per frame, bytesPerPacket, bytesPerFrame
bool CAAudioFileFormats::InferDataFormatFromFileFormat(AudioFileTypeID filetype, CAStreamBasicDescription &fmt)
{
// if the file format only supports one data format
for (int i = 0; i < mNumFileFormats; ++i) {
FileFormatInfo *ffi = &mFileFormats[i];
ffi->LoadDataFormats();
if (ffi->mFileTypeID == filetype && ffi->mNumDataFormats > 0) {
DataFormatInfo *dfi = &ffi->mDataFormats[0];
if (ffi->mNumDataFormats > 1) {
// file can contain multiple data formats. Take PCM if it's there.
for (int j = 0; j < ffi->mNumDataFormats; ++j) {
if (ffi->mDataFormats[j].mFormatID == kAudioFormatLinearPCM) {
dfi = &ffi->mDataFormats[j];
break;
}
}
}
memset(&fmt, 0, sizeof(fmt));
fmt.mFormatID = dfi->mFormatID;
if (dfi->mNumVariants > 0) {
// take the first variant as a default
fmt = dfi->mVariants[0];
if (dfi->mNumVariants > 1 && dfi->mFormatID == kAudioFormatLinearPCM) {
// look for a 16-bit variant as a better default
for (int j = 0; j < dfi->mNumVariants; ++j) {
AudioStreamBasicDescription *desc = &dfi->mVariants[j];
if (desc->mBitsPerChannel == 16) {
fmt = *desc;
break;
}
}
}
}
return true;
}
}
return false;
}
bool CAAudioFileFormats::InferFileFormatFromFilename(CFStringRef filename, AudioFileTypeID &filetype)
{
bool result = false;
CFRange range = CFStringFind(filename, CFSTR("."), kCFCompareBackwards);
if (range.location == kCFNotFound) return false;
range.location += 1;
range.length = CFStringGetLength(filename) - range.location;
CFStringRef ext = CFStringCreateWithSubstring(NULL, filename, range);
for (int i = 0; i < mNumFileFormats; ++i) {
FileFormatInfo *ffi = &mFileFormats[i];
if (ffi->MatchExtension(ext)) {
filetype = ffi->mFileTypeID;
result = true;
break;
}
}
CFRelease(ext);
return result;
}
bool CAAudioFileFormats::InferFileFormatFromFilename(const char *filename, AudioFileTypeID &filetype)
{
if (filename == NULL) return false;
CFStringRef cfname = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
bool result = InferFileFormatFromFilename(cfname, filetype);
CFRelease(cfname);
return result;
}
bool CAAudioFileFormats::InferFileFormatFromDataFormat(const CAStreamBasicDescription &fmt,
AudioFileTypeID &filetype)
{
// if there's exactly one file format that supports this data format
FileFormatInfo *theFileFormat = NULL;
for (int i = 0; i < mNumFileFormats; ++i) {
FileFormatInfo *ffi = &mFileFormats[i];
ffi->LoadDataFormats();
DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats;
for ( ; dfi < dfiend; ++dfi)
if (dfi->mFormatID == fmt.mFormatID) {
if (theFileFormat != NULL)
return false; // ambiguous
theFileFormat = ffi; // got a candidate
}
}
if (theFileFormat == NULL)
return false;
filetype = theFileFormat->mFileTypeID;
return true;
}
bool CAAudioFileFormats::IsKnownDataFormat(OSType dataFormat)
{
for (int i = 0; i < mNumFileFormats; ++i) {
FileFormatInfo *ffi = &mFileFormats[i];
ffi->LoadDataFormats();
DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats;
for ( ; dfi < dfiend; ++dfi)
if (dfi->mFormatID == dataFormat)
return true;
}
return false;
}
CAAudioFileFormats::FileFormatInfo * CAAudioFileFormats::FindFileFormat(UInt32 formatID)
{
for (int i = 0; i < mNumFileFormats; ++i) {
FileFormatInfo *ffi = &mFileFormats[i];
if (ffi->mFileTypeID == formatID)
return ffi;
}
return NULL;
}
bool CAAudioFileFormats::FileFormatInfo::AnyWritableFormats()
{
LoadDataFormats();
DataFormatInfo *dfi = mDataFormats, *dfiend = dfi + mNumDataFormats;
for ( ; dfi < dfiend; ++dfi)
if (dfi->mWritable)
return true;
return false;
}
char *OSTypeToStr(char *buf, size_t bufsize, OSType t)
{
if (bufsize > 0) {
char *p = buf, *pend = buf + bufsize;
char str[4] = {0}, *q = str;
*(UInt32 *)str = CFSwapInt32HostToBig(t);
for (int i = 0; i < 4 && p < pend; ++i) {
if (isprint(*q) && *q != '\\')
*p++ = *q++;
else {
snprintf(p, pend - p, "\\x%02x", *q++);
p += 4;
}
}
if (p >= pend) p = pend - 1;
*p = '\0';
}
return buf;
}
int StrToOSType(const char *str, OSType &t)
{
char buf[4];
const char *p = str;
int x;
for (int i = 0; i < 4; ++i) {
if (*p != '\\') {
if ((buf[i] = *p++) == '\0') {
// special-case for 'aac ': if we only got three characters, assume the last was a space
if (i == 3) {
--p;
buf[i] = ' ';
break;
}
goto fail;
}
} else {
if (*++p != 'x') goto fail;
if (sscanf(++p, "%02X", &x) != 1) goto fail;
buf[i] = x;
p += 2;
}
}
t = CFSwapInt32BigToHost(*(UInt32 *)buf);
return static_cast<int>(p - str);
fail:
return 0;
}
#if DEBUG
void CAAudioFileFormats::DebugPrint()
{
for (int i = 0; i < mNumFileFormats; ++i)
mFileFormats[i].DebugPrint();
}
void CAAudioFileFormats::FileFormatInfo::DebugPrint()
{
char ftype[20];
char ftypename[64];
CFStringGetCString(mFileTypeName, ftypename, sizeof(ftypename), kCFStringEncodingUTF8);
printf("File type: '%s' = %s\n Extensions:", OSTypeToStr(ftype, sizeof(ftype), mFileTypeID), ftypename);
int i, n = NumberOfExtensions();
for (i = 0; i < n; ++i) {
GetExtension(i, ftype, sizeof(ftype));
printf(" .%s", ftype);
}
LoadDataFormats();
printf("\n Formats:\n");
for (i = 0; i < mNumDataFormats; ++i)
mDataFormats[i].DebugPrint();
}
void CAAudioFileFormats::DataFormatInfo::DebugPrint()
{
char buf[20];
static const char *ny[] = { "not ", "" };
printf(" '%s': %sreadable %swritable\n", OSTypeToStr(buf, sizeof(buf), mFormatID), ny[mReadable], ny[mWritable]);
for (int i = 0; i < mNumVariants; ++i) {
CAStreamBasicDescription desc(mVariants[i]);
desc.PrintFormat(stdout, " ", "");
//printf(" %d bytes/frame\n", desc.mBytesPerFrame);
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More