alternative new version of the AppleUtility library
This commit is contained in:
580
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACBaseCodec.cpp
Normal file
580
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACBaseCodec.cpp
Normal 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;
|
||||
}
|
||||
147
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACBaseCodec.h
Normal file
147
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACBaseCodec.h
Normal 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
|
||||
329
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACCodec.cpp
Normal file
329
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACCodec.cpp
Normal 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
|
||||
115
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACCodec.h
Normal file
115
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACCodec.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
105
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACSimpleCodec.h
Normal file
105
libs/appleutility/CoreAudio/AudioCodecs/ACPublic/ACSimpleCodec.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
125
libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.h
Normal file
125
libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.h
Normal 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
|
||||
1966
libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.cpp
Normal file
1966
libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.cpp
Normal file
File diff suppressed because it is too large
Load Diff
667
libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.h
Normal file
667
libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.h
Normal 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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
689
libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp
Normal file
689
libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
372
libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.h
Normal file
372
libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.h
Normal 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
|
||||
2393
libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUBase/AUBase.cpp
Normal file
2393
libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUBase/AUBase.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1048
libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUBase/AUBase.h
Normal file
1048
libs/appleutility/CoreAudio/AudioUnits/AUPublic/AUBase/AUBase.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 *)¶ms->params[_index + 1];
|
||||
#else
|
||||
// parameters in reverse order, then comp instance
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->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 *)¶ms->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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
@@ -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 ¶m, 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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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 ¶m, 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(¶mValue);
|
||||
|
||||
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, ¤tPreset, &theSize);
|
||||
|
||||
if (result == noErr) {
|
||||
#ifndef __LP64__
|
||||
if (inProp.mPropertyID == kAudioUnitProperty_CurrentPreset && currentPreset.presetName)
|
||||
CFRetain (currentPreset.presetName);
|
||||
#endif
|
||||
HandlePropertyChange(currentPreset);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -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 ¶m, 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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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__
|
||||
@@ -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, ¬eState); // 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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 *)¶ms->params[_index + 1];
|
||||
#else
|
||||
// parameters in reverse order, then comp instance
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->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 *)¶ms->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
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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 *)¶ms->params[_index + 1];
|
||||
#else
|
||||
// parameters in reverse order, then comp instance
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->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 *)¶ms->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
|
||||
@@ -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__
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
169
libs/appleutility/CoreAudio/PublicUtility/AUOutputBL.cpp
Normal file
169
libs/appleutility/CoreAudio/PublicUtility/AUOutputBL.cpp
Normal 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
|
||||
|
||||
118
libs/appleutility/CoreAudio/PublicUtility/AUOutputBL.h
Normal file
118
libs/appleutility/CoreAudio/PublicUtility/AUOutputBL.h
Normal 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__
|
||||
139
libs/appleutility/CoreAudio/PublicUtility/AUParamInfo.cpp
Normal file
139
libs/appleutility/CoreAudio/PublicUtility/AUParamInfo.cpp
Normal 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 ¶mInfo = 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;
|
||||
}
|
||||
112
libs/appleutility/CoreAudio/PublicUtility/AUParamInfo.h
Normal file
112
libs/appleutility/CoreAudio/PublicUtility/AUParamInfo.h
Normal 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; }
|
||||
};
|
||||
227
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMap.cpp
Normal file
227
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMap.cpp
Normal 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);
|
||||
}
|
||||
541
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMap.h
Normal file
541
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMap.h
Normal 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
|
||||
233
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMapManager.cpp
Normal file
233
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMapManager.cpp
Normal 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;
|
||||
}
|
||||
102
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMapManager.h
Normal file
102
libs/appleutility/CoreAudio/PublicUtility/CAAUMIDIMapManager.h
Normal 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
|
||||
400
libs/appleutility/CoreAudio/PublicUtility/CAAUParameter.cpp
Normal file
400
libs/appleutility/CoreAudio/PublicUtility/CAAUParameter.cpp
Normal 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
|
||||
191
libs/appleutility/CoreAudio/PublicUtility/CAAUParameter.h
Normal file
191
libs/appleutility/CoreAudio/PublicUtility/CAAUParameter.h
Normal 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__
|
||||
707
libs/appleutility/CoreAudio/PublicUtility/CAAUProcessor.cpp
Normal file
707
libs/appleutility/CoreAudio/PublicUtility/CAAUProcessor.cpp
Normal 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
|
||||
293
libs/appleutility/CoreAudio/PublicUtility/CAAUProcessor.h
Normal file
293
libs/appleutility/CoreAudio/PublicUtility/CAAUProcessor.h
Normal 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__
|
||||
305
libs/appleutility/CoreAudio/PublicUtility/CAAtomic.h
Normal file
305
libs/appleutility/CoreAudio/PublicUtility/CAAtomic.h
Normal 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__
|
||||
239
libs/appleutility/CoreAudio/PublicUtility/CAAtomicStack.h
Normal file
239
libs/appleutility/CoreAudio/PublicUtility/CAAtomicStack.h
Normal 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__
|
||||
239
libs/appleutility/CoreAudio/PublicUtility/CAAudioBufferList.cpp
Normal file
239
libs/appleutility/CoreAudio/PublicUtility/CAAudioBufferList.cpp
Normal 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;
|
||||
}
|
||||
108
libs/appleutility/CoreAudio/PublicUtility/CAAudioBufferList.h
Normal file
108
libs/appleutility/CoreAudio/PublicUtility/CAAudioBufferList.h
Normal 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
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
199
libs/appleutility/CoreAudio/PublicUtility/CAAudioChannelLayout.h
Normal file
199
libs/appleutility/CoreAudio/PublicUtility/CAAudioChannelLayout.h
Normal 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
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
424
libs/appleutility/CoreAudio/PublicUtility/CAAudioFileFormats.cpp
Normal file
424
libs/appleutility/CoreAudio/PublicUtility/CAAudioFileFormats.cpp
Normal 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
Reference in New Issue
Block a user