@@ -4,6 +4,28 @@ JUCE breaking changes | |||
develop | |||
======= | |||
Change | |||
------ | |||
Resource forks are no longer generated for Audio Unit plug-ins. | |||
Possible Issues | |||
--------------- | |||
New builds of JUCE Audio Units may no longer load in old hosts that use the | |||
Component Manager to discover plug-ins. | |||
Workaround | |||
---------- | |||
No workaround is available. | |||
Rationale | |||
--------- | |||
The Component Manager is deprecated in macOS 10.8 and later, so the majority of | |||
hosts have now implemented support for the new plist-based discovery mechanism. | |||
The new AudioUnitSDK (https://github.com/apple/AudioUnitSDK) provided by Apple | |||
to replace the old Core Audio Utility Classes no longer includes the files | |||
required to generate resource forks. | |||
Change | |||
------ | |||
Previously, the AudioProcessorGraph would call processBlockBypassed on any | |||
@@ -94,7 +94,7 @@ The JUCE framework contains the following dependencies: | |||
- [Oboe](modules/juce_audio_devices/native/oboe/) ([Apache 2.0](modules/juce_audio_devices/native/oboe/LICENSE)) | |||
- [FLAC](modules/juce_audio_formats/codecs/flac/) ([BSD](modules/juce_audio_formats/codecs/flac/Flac%20Licence.txt)) | |||
- [Ogg Vorbis](modules/juce_audio_formats/codecs/oggvorbis/) ([BSD](modules/juce_audio_formats/codecs/oggvorbis/Ogg%20Vorbis%20Licence.txt)) | |||
- [CoreAudioUtilityClasses](modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/) ([Apple](modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp)) | |||
- [AudioUnitSDK](modules/juce_audio_plugin_client/AU/AudioUnitSDK/) ([Apache 2.0](modules/juce_audio_plugin_client/AU/AudioUnitSDK/LICENSE.txt)) | |||
- [AUResources.r](modules/juce_audio_plugin_client/AUResources.r) ([Apple](modules/juce_audio_plugin_client/AUResources.r)) | |||
- [LV2](modules/juce_audio_processors/format_types/LV2_SDK/) ([ISC](modules/juce_audio_processors/format_types/LV2_SDK/lv2/COPYING)) | |||
- [pslextensions](modules/juce_audio_processors/format_types/pslextensions/ipslcontextinfo.h) ([Public domain](modules/juce_audio_processors/format_types/pslextensions/ipslcontextinfo.h)) | |||
@@ -849,7 +849,7 @@ EXCLUDE = build/juce_graphics/image_formats \ | |||
build/juce_audio_formats/codecs/flac \ | |||
build/juce_audio_formats/codecs/oggvorbis \ | |||
build/juce_audio_devices/native \ | |||
build/juce_audio_plugin_client/AU/CoreAudioUtilityClasses \ | |||
build/juce_audio_plugin_client/AU/AudioUnitSDK \ | |||
build/juce_browser_plugin_client/juce_browser_plugin.h \ | |||
build/juce_core/native \ | |||
build/juce_events/native \ | |||
@@ -327,6 +327,8 @@ function(_juce_add_plugin_wrapper_target format path out_path) | |||
_juce_link_frameworks("${target_name}" INTERFACE AudioUnit) | |||
endif() | |||
elseif(format STREQUAL "AU") | |||
target_compile_features("${target_name}" INTERFACE cxx_std_17) | |||
target_include_directories("${target_name}" INTERFACE "${out_path}/juce_audio_plugin_client/AU") | |||
_juce_link_frameworks("${target_name}" INTERFACE AudioUnit CoreAudioKit) | |||
endif() | |||
endfunction() | |||
@@ -87,12 +87,6 @@ set_property(GLOBAL PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD FALSE) | |||
if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) | |||
_juce_create_pkgconfig_target(JUCE_CURL_LINUX_DEPS libcurl) | |||
_juce_create_pkgconfig_target(JUCE_BROWSER_LINUX_DEPS webkit2gtk-4.0 gtk+-x11-3.0) | |||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") | |||
find_program(JUCE_XCRUN xcrun) | |||
if(NOT JUCE_XCRUN) | |||
message(WARNING "failed to find xcrun; older resource-based AU plug-ins may not work correctly") | |||
endif() | |||
endif() | |||
# We set up default/fallback copy dirs here. If you need different copy dirs, use | |||
@@ -153,67 +147,6 @@ endfunction() | |||
# ================================================================================================== | |||
function(_juce_add_au_resource_fork shared_code_target au_target) | |||
if(NOT JUCE_XCRUN) | |||
return() | |||
endif() | |||
get_target_property(product_name ${shared_code_target} JUCE_PRODUCT_NAME) | |||
get_target_property(module_sources juce::juce_audio_plugin_client_AU INTERFACE_SOURCES) | |||
list(FILTER module_sources INCLUDE REGEX "/juce_audio_plugin_client_AU.r$") | |||
if(NOT module_sources) | |||
message(FATAL_ERROR "Failed to find AU resource file input") | |||
endif() | |||
list(GET module_sources 0 au_rez_sources) | |||
get_target_property(juce_library_code ${shared_code_target} JUCE_GENERATED_SOURCES_DIRECTORY) | |||
# We don't want our AU AppConfig.h to end up on peoples' include paths if we can help it | |||
set(secret_au_resource_dir "${juce_library_code}/${au_target}/secret") | |||
set(secret_au_plugindefines "${secret_au_resource_dir}/JucePluginDefines.h") | |||
set(au_rez_output "${secret_au_resource_dir}/${product_name}.rsrc") | |||
target_sources(${au_target} PRIVATE "${au_rez_output}") | |||
set_source_files_properties("${au_rez_output}" PROPERTIES | |||
GENERATED TRUE | |||
MACOSX_PACKAGE_LOCATION Resources) | |||
set(defs_file $<GENEX_EVAL:$<TARGET_PROPERTY:${shared_code_target},JUCE_DEFS_FILE>>) | |||
# Passing all our compile definitions using generator expressions is really painful | |||
# because some of the definitions have pipes and quotes and dollars and goodness-knows | |||
# what else that the shell would very much like to claim for itself, thank you very much. | |||
# CMake definitely knows how to escape all these things, because it's perfectly happy to pass | |||
# them to compiler invocations, but I have no idea how to get it to escape them | |||
# in a custom command. | |||
# In the end, it's simplest to generate a special single-purpose appconfig just for the | |||
# resource compiler. | |||
add_custom_command(OUTPUT "${secret_au_plugindefines}" | |||
COMMAND juce::juceaide auplugindefines "${defs_file}" "${secret_au_plugindefines}" | |||
DEPENDS "${defs_file}" | |||
VERBATIM) | |||
add_custom_command(OUTPUT "${au_rez_output}" | |||
COMMAND "${JUCE_XCRUN}" Rez | |||
-d "ppc_$ppc" -d "i386_$i386" -d "ppc64_$ppc64" -d "x86_64_$x86_64" -d "arm64_$arm64" | |||
-I "${secret_au_resource_dir}" | |||
-I "/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers" | |||
-I "${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/AudioUnit.framework/Headers" | |||
-isysroot "${CMAKE_OSX_SYSROOT}" | |||
"${au_rez_sources}" | |||
-useDF | |||
-o "${au_rez_output}" | |||
DEPENDS "${secret_au_plugindefines}" | |||
VERBATIM) | |||
set(au_resource_directory "$<TARGET_BUNDLE_DIR:${au_target}>/Contents/Resources") | |||
endfunction() | |||
# ================================================================================================== | |||
# Ideally, we'd check the preprocessor defs on the target to see whether | |||
# JUCE_USE_CURL, JUCE_WEB_BROWSER, or JUCE_IN_APP_PURCHASES have been explicitly turned off, | |||
# and then link libraries as appropriate. | |||
@@ -1285,10 +1218,6 @@ function(_juce_configure_plugin_targets target) | |||
_juce_configure_app_bundle(${target} ${target}_Standalone) | |||
endif() | |||
if(TARGET ${target}_AU) | |||
_juce_add_au_resource_fork(${target} ${target}_AU) | |||
endif() | |||
if(TARGET ${target}_AAX) | |||
target_link_libraries(${target}_AAX PRIVATE juce_aax_sdk) | |||
endif() | |||
@@ -1048,7 +1048,7 @@ public: | |||
struct XcodeTarget : build_tools::ProjectType::Target | |||
{ | |||
//============================================================================== | |||
XcodeTarget (build_tools::ProjectType::Target::Type targetType, const XcodeProjectExporter& exporter) | |||
XcodeTarget (Type targetType, const XcodeProjectExporter& exporter) | |||
: Target (targetType), | |||
owner (exporter) | |||
{ | |||
@@ -1699,10 +1699,17 @@ public: | |||
s.set ("CODE_SIGN_ENTITLEMENTS", getEntitlementsFilename().quoted()); | |||
{ | |||
auto cppStandard = owner.project.getCppStandardString(); | |||
const auto cppStandard = [&]() -> String | |||
{ | |||
if (owner.project.getCppStandardString() == "latest") | |||
return owner.project.getLatestNumberedCppStandardString(); | |||
// The AudioUnitSDK requires C++17 | |||
if (type == AudioUnitPlugIn) | |||
return "17"; | |||
if (cppStandard == "latest") | |||
cppStandard = owner.project.getLatestNumberedCppStandardString(); | |||
return owner.project.getCppStandardString(); | |||
}(); | |||
s.set ("CLANG_CXX_LANGUAGE_STANDARD", (String (owner.shouldUseGNUExtensions() ? "gnu++" | |||
: "c++") + cppStandard).quoted()); | |||
@@ -1970,10 +1977,15 @@ public: | |||
if (owner.project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client")) | |||
{ | |||
// Needed to compile .r files | |||
paths.add (owner.getModuleFolderRelativeToProject ("juce_audio_plugin_client") | |||
.rebased (owner.projectFolder, owner.getTargetFolder(), build_tools::RelativePath::buildTargetFolder) | |||
.toUnixStyle()); | |||
const auto pluginClientModule = owner.getModuleFolderRelativeToProject ("juce_audio_plugin_client"); | |||
for (const auto& path : { pluginClientModule, // For AU resource fork | |||
pluginClientModule.getChildFile ("AU") }) // For AudioUnitSDK includes | |||
{ | |||
paths.add (path.rebased (owner.projectFolder, | |||
owner.getTargetFolder(), | |||
build_tools::RelativePath::buildTargetFolder) | |||
.toUnixStyle()); | |||
} | |||
} | |||
sanitiseAndEscapeSearchPaths (config, paths); | |||
@@ -0,0 +1,733 @@ | |||
/*! | |||
@file AudioUnitSDK/AUBase.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUBase_h | |||
#define AudioUnitSDK_AUBase_h | |||
// module | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
#include <AudioUnitSDK/AUInputElement.h> | |||
#include <AudioUnitSDK/AUMIDIUtility.h> | |||
#include <AudioUnitSDK/AUOutputElement.h> | |||
#include <AudioUnitSDK/AUPlugInDispatch.h> | |||
#include <AudioUnitSDK/AUScopeElement.h> | |||
#include <AudioUnitSDK/AUUtility.h> | |||
// OS | |||
#include <TargetConditionals.h> | |||
// std | |||
#include <algorithm> | |||
#include <array> | |||
#include <memory> | |||
#include <mutex> | |||
#include <thread> | |||
#include <vector> | |||
// ________________________________________________________________________ | |||
namespace ausdk { | |||
/*! | |||
@class AUBase | |||
@brief Abstract base class for an Audio Unit implementation. | |||
*/ | |||
class AUBase : public ComponentBase { | |||
public: | |||
constexpr static double kAUDefaultSampleRate = 44100.0; | |||
#if !TARGET_OS_WIN32 | |||
constexpr static UInt32 kAUDefaultMaxFramesPerSlice = 1156; | |||
// this allows enough default frames for a 512 dest 44K and SRC from 96K | |||
// add a padding of 4 frames for any vector rounding | |||
#else | |||
constexpr static UInt32 kAUDefaultMaxFramesPerSlice = 2048; | |||
#endif | |||
AUBase(AudioComponentInstance inInstance, UInt32 numInputElements, UInt32 numOutputElements, | |||
UInt32 numGroupElements = 0); | |||
~AUBase() override; | |||
AUBase(const AUBase&) = delete; | |||
AUBase(AUBase&&) = delete; | |||
AUBase& operator=(const AUBase&) = delete; | |||
AUBase& operator=(AUBase&&) = delete; | |||
/// Called immediately after construction, when virtual methods work. Or, a subclass may call | |||
/// this in order to have access to elements in its constructor. | |||
void CreateElements(); | |||
virtual void CreateExtendedElements() {} | |||
#pragma mark - | |||
#pragma mark AU dispatch | |||
// ________________________________________________________________________ | |||
// Virtual methods (mostly) directly corresponding to the entry points. Many of these | |||
// have useful implementations here and will not need overriding. | |||
/// Implements the entry point and ensures that Initialize is called exactly once from an | |||
/// uninitialized state. | |||
OSStatus DoInitialize(); | |||
// Overrides to this method can assume that they will only be called exactly once | |||
// when transitioning from an uninitialized state. | |||
virtual OSStatus Initialize(); | |||
[[nodiscard]] bool IsInitialized() const noexcept { return mInitialized; } | |||
[[nodiscard]] bool HasBegunInitializing() const noexcept { return mHasBegunInitializing; } | |||
/// Implements the entry point and ensures that Cleanup is called exactly once from an | |||
/// initialized state. | |||
void DoCleanup(); | |||
// Overrides to this method can assume that they will only be called exactly once | |||
// when transitioning from an initialized state to an uninitialized state. | |||
virtual void Cleanup(); | |||
virtual OSStatus Reset(AudioUnitScope inScope, AudioUnitElement inElement); | |||
// Note about GetPropertyInfo, GetProperty, SetProperty: | |||
// Certain properties are trapped out in these dispatch functions and handled with different | |||
// virtual methods. (To discourage hacks and keep vtable size down, these are non-virtual) | |||
OSStatus DispatchGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable); | |||
OSStatus DispatchGetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, void* outData); | |||
OSStatus DispatchSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize); | |||
OSStatus DispatchRemovePropertyValue( | |||
AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement); | |||
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& 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); | |||
virtual OSStatus RemovePropertyValue( | |||
AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement); | |||
virtual OSStatus AddPropertyListener( | |||
AudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcRefCon); | |||
virtual OSStatus RemovePropertyListener(AudioUnitPropertyID inID, | |||
AudioUnitPropertyListenerProc inProc, void* inProcRefCon, bool refConSpecified); | |||
virtual OSStatus SetRenderNotification(AURenderCallback inProc, void* inRefCon); | |||
virtual OSStatus RemoveRenderNotification(AURenderCallback inProc, void* inRefCon); | |||
virtual OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, AudioUnitParameterValue& outValue); | |||
virtual OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, AudioUnitParameterValue inValue, UInt32 inBufferOffsetInFrames); | |||
[[nodiscard]] virtual bool CanScheduleParameters() const = 0; | |||
virtual OSStatus ScheduleParameter( | |||
const AudioUnitParameterEvent* inParameterEvent, UInt32 inNumEvents); | |||
OSStatus DoRender(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, | |||
UInt32 inBusNumber, UInt32 inFramesToProcess, AudioBufferList& ioData); | |||
OSStatus DoProcess(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, | |||
UInt32 inFramesToProcess, AudioBufferList& ioData); | |||
OSStatus DoProcessMultiple(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, UInt32 inFramesToProcess, | |||
UInt32 inNumberInputBufferLists, const AudioBufferList** inInputBufferLists, | |||
UInt32 inNumberOutputBufferLists, AudioBufferList** ioOutputBufferLists); | |||
virtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& /*ioActionFlags*/, | |||
const AudioBufferList& /*inBuffer*/, AudioBufferList& /*outBuffer*/, | |||
UInt32 /*inFramesToProcess*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
virtual OSStatus ProcessMultipleBufferLists(AudioUnitRenderActionFlags& /*ioActionFlags*/, | |||
UInt32 /*inFramesToProcess*/, UInt32 /*inNumberInputBufferLists*/, | |||
const AudioBufferList** /*inInputBufferLists*/, UInt32 /*inNumberOutputBufferLists*/, | |||
AudioBufferList** /*ioOutputBufferLists*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
virtual OSStatus ComplexRender(AudioUnitRenderActionFlags& /*ioActionFlags*/, | |||
const AudioTimeStamp& /*inTimeStamp*/, UInt32 /*inOutputBusNumber*/, | |||
UInt32 /*inNumberOfPackets*/, UInt32* /*outNumberOfPackets*/, | |||
AudioStreamPacketDescription* /*outPacketDescriptions*/, AudioBufferList& /*ioData*/, | |||
void* /*outMetadata*/, UInt32* /*outMetadataByteSize*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
// Override this method if your AU processes multiple output busses completely independently -- | |||
// you'll want to just call Render without the NeedsToRender check. | |||
// Otherwise, override Render(). | |||
// | |||
// N.B. Implementations of this method can assume that the output's buffer list has already been | |||
// prepared and access it with GetOutput(inBusNumber)->GetBufferList() instead of | |||
// GetOutput(inBusNumber)->PrepareBuffer(nFrames) -- if PrepareBuffer is called, a | |||
// copy may occur after rendering. | |||
virtual OSStatus RenderBus(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames) | |||
{ | |||
if (NeedsToRender(inTimeStamp)) { | |||
return Render(ioActionFlags, inTimeStamp, inNumberFrames); | |||
} | |||
return noErr; // was presumably already rendered via another bus | |||
} | |||
// N.B. For a unit with only one output bus, it can assume in its implementation of this | |||
// method that the output's buffer list has already been prepared and access it with | |||
// GetOutput(0)->GetBufferList() instead of GetOutput(0)->PrepareBuffer(nFrames) | |||
// -- if PrepareBuffer is called, a copy may occur after rendering. | |||
virtual OSStatus Render(AudioUnitRenderActionFlags& /*ioActionFlags*/, | |||
const AudioTimeStamp& /*inTimeStamp*/, UInt32 /*inNumberFrames*/) | |||
{ | |||
return noErr; | |||
} | |||
#pragma mark - | |||
#pragma mark Property Dispatch | |||
// ________________________________________________________________________ | |||
// These are called from DispatchGetProperty/DispatchGetPropertyInfo/DispatchSetProperty | |||
virtual bool BusCountWritable(AudioUnitScope /*inScope*/) { return false; } | |||
virtual OSStatus SetBusCount(AudioUnitScope inScope, UInt32 inCount); | |||
virtual OSStatus SetConnection(const AudioUnitConnection& inConnection); | |||
virtual OSStatus SetInputCallback( | |||
UInt32 inPropertyID, AudioUnitElement inElement, AURenderCallback inProc, void* inRefCon); | |||
virtual OSStatus GetParameterList( | |||
AudioUnitScope inScope, AudioUnitParameterID* outParameterList, UInt32& outNumParameters); | |||
// outParameterList may be a null pointer | |||
virtual OSStatus GetParameterInfo(AudioUnitScope inScope, AudioUnitParameterID inParameterID, | |||
AudioUnitParameterInfo& outParameterInfo); | |||
virtual OSStatus GetParameterHistoryInfo(AudioUnitScope inScope, | |||
AudioUnitParameterID inParameterID, Float32& outUpdatesPerSecond, | |||
Float32& outHistoryDurationInSeconds); | |||
virtual OSStatus SaveState(CFPropertyListRef* outData); | |||
virtual void SaveExtendedScopes(CFMutableDataRef /*outData*/) {} | |||
virtual OSStatus RestoreState(CFPropertyListRef plist); | |||
virtual OSStatus GetParameterValueStrings( | |||
AudioUnitScope inScope, AudioUnitParameterID inParameterID, CFArrayRef* outStrings); | |||
virtual OSStatus CopyClumpName(AudioUnitScope inScope, UInt32 inClumpID, | |||
UInt32 inDesiredNameLength, CFStringRef* outClumpName); | |||
virtual OSStatus GetPresets(CFArrayRef* outData) const; | |||
/// Set the default preset for the unit. The number of the preset must be >= 0 and the name | |||
/// should be valid, or the preset will be rejected. | |||
bool SetAFactoryPresetAsCurrent(const AUPreset& inPreset); | |||
// Called when the host sets a new, valid preset. | |||
// If this is a valid preset, then the subclass sets its state to that preset | |||
// and returns noErr. | |||
// If not a valid preset, return an error, and the pre-existing preset is restored. | |||
virtual OSStatus NewFactoryPresetSet(const AUPreset& inNewFactoryPreset); | |||
virtual OSStatus NewCustomPresetSet(const AUPreset& inNewCustomPreset); | |||
virtual CFURLRef CopyIconLocation(); | |||
// default is no latency, and unimplemented tail time | |||
virtual Float64 GetLatency() { return 0.0; } | |||
virtual Float64 GetTailTime() { return 0.0; } | |||
virtual bool SupportsTail() { return false; } | |||
// Stream formats: scope will always be input or output | |||
bool IsStreamFormatWritable(AudioUnitScope scope, AudioUnitElement element); | |||
virtual bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) = 0; | |||
// pass in a pointer to get the struct, and num channel infos | |||
// you can pass in NULL to just get the number | |||
// a return value of 0 (the default in AUBase) means the property is not supported... | |||
virtual UInt32 SupportedNumChannels(const AUChannelInfo** outInfo); | |||
/// Will only be called after StreamFormatWritable has succeeded. Default implementation | |||
/// requires non-interleaved native-endian 32-bit float, any sample rate, any number of | |||
/// channels; override when other formats are supported. A subclass's override can choose to | |||
/// always return true and trap invalid formats in ChangeStreamFormat. | |||
virtual bool ValidFormat(AudioUnitScope inScope, AudioUnitElement inElement, | |||
const AudioStreamBasicDescription& inNewFormat); | |||
virtual AudioStreamBasicDescription GetStreamFormat( | |||
AudioUnitScope inScope, AudioUnitElement inElement); | |||
// Will only be called after StreamFormatWritable | |||
// and ValidFormat have succeeded. | |||
virtual OSStatus ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement, | |||
const AudioStreamBasicDescription& inPrevFormat, | |||
const AudioStreamBasicDescription& inNewFormat); | |||
// ________________________________________________________________________ | |||
// Methods useful for subclasses | |||
AUScope& GetScope(AudioUnitScope inScope) | |||
{ | |||
if (inScope >= kNumScopes) { | |||
AUScope* const scope = GetScopeExtended(inScope); | |||
ThrowQuietIf(scope == nullptr, kAudioUnitErr_InvalidScope); | |||
return *scope; | |||
} | |||
return mScopes[inScope]; // NOLINT | |||
} | |||
virtual AUScope* GetScopeExtended(AudioUnitScope /*inScope*/) { return nullptr; } | |||
AUScope& GlobalScope() { return mScopes[kAudioUnitScope_Global]; } | |||
AUScope& Inputs() { return mScopes[kAudioUnitScope_Input]; } | |||
AUScope& Outputs() { return mScopes[kAudioUnitScope_Output]; } | |||
AUScope& Groups() { return mScopes[kAudioUnitScope_Group]; } | |||
AUElement* Globals() { return mScopes[kAudioUnitScope_Global].GetElement(0); } | |||
void SetNumberOfElements(AudioUnitScope inScope, UInt32 numElements); | |||
virtual std::unique_ptr<AUElement> CreateElement( | |||
AudioUnitScope scope, AudioUnitElement element); | |||
AUElement* GetElement(AudioUnitScope inScope, AudioUnitElement inElement) | |||
{ | |||
return GetScope(inScope).GetElement(inElement); | |||
} | |||
AUSDK_DEPRECATED("Use IOElement()") | |||
AUIOElement* GetIOElement(AudioUnitScope inScope, AudioUnitElement inElement) | |||
{ | |||
return &IOElement(inScope, inElement); | |||
} | |||
AUIOElement& IOElement(AudioUnitScope inScope, AudioUnitElement inElement) | |||
{ | |||
return *GetScope(inScope).GetIOElement(inElement); | |||
} | |||
AUSDK_DEPRECATED("Use Element()") | |||
AUElement* SafeGetElement(AudioUnitScope inScope, AudioUnitElement inElement) | |||
{ | |||
return &Element(inScope, inElement); | |||
} | |||
AUElement& Element(AudioUnitScope inScope, AudioUnitElement inElement) | |||
{ | |||
return *GetScope(inScope).SafeGetElement(inElement); | |||
} | |||
AUSDK_DEPRECATED("Use Input()") | |||
AUInputElement* GetInput(AudioUnitElement inElement) { return &Input(inElement); } | |||
AUInputElement& Input(AudioUnitElement inElement) | |||
{ | |||
return static_cast<AUInputElement&>(*Inputs().SafeGetElement(inElement)); // NOLINT downcast | |||
} | |||
AUSDK_DEPRECATED("Use Output()") | |||
AUOutputElement* GetOutput(AudioUnitElement inElement) { return &Output(inElement); } | |||
AUOutputElement& Output(AudioUnitElement inElement) | |||
{ | |||
return static_cast<AUOutputElement&>( // NOLINT downcast | |||
*Outputs().SafeGetElement(inElement)); | |||
} | |||
AUSDK_DEPRECATED("Use Group()") | |||
AUElement* GetGroup(AudioUnitElement inElement) { return &Group(inElement); } | |||
AUElement& Group(AudioUnitElement inElement) { return *Groups().SafeGetElement(inElement); } | |||
OSStatus PullInput(UInt32 inBusNumber, AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, UInt32 inNumberFrames) | |||
{ | |||
AUInputElement& input = Input(inBusNumber); // throws if error | |||
return input.PullInput(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames); | |||
} | |||
[[nodiscard]] UInt32 GetMaxFramesPerSlice() const noexcept { return mMaxFramesPerSlice; } | |||
[[nodiscard]] bool UsesFixedBlockSize() const noexcept { return mUsesFixedBlockSize; } | |||
void SetUsesFixedBlockSize(bool inUsesFixedBlockSize) noexcept | |||
{ | |||
mUsesFixedBlockSize = inUsesFixedBlockSize; | |||
} | |||
[[nodiscard]] virtual bool InRenderThread() const | |||
{ | |||
return std::this_thread::get_id() == mRenderThreadID; | |||
} | |||
/// Says whether an input is connected or has a callback. | |||
bool HasInput(AudioUnitElement inElement) | |||
{ | |||
auto* const in = | |||
static_cast<AUInputElement*>(Inputs().GetElement(inElement)); // NOLINT downcast | |||
return in != nullptr && in->IsActive(); | |||
} | |||
virtual void PropertyChanged( | |||
AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement); | |||
// These calls can be used to call a Host's Callbacks. The method returns -1 if the host | |||
// hasn't supplied the callback. Any other result is returned by the host. | |||
// As in the API contract, for a parameter's value, you specify a pointer | |||
// to that data type. Specify NULL for a parameter that you are not interested | |||
// as this can save work in the host. | |||
OSStatus CallHostBeatAndTempo(Float64* outCurrentBeat, Float64* outCurrentTempo) const | |||
{ | |||
return (mHostCallbackInfo.beatAndTempoProc != nullptr | |||
? (*mHostCallbackInfo.beatAndTempoProc)( | |||
mHostCallbackInfo.hostUserData, outCurrentBeat, outCurrentTempo) | |||
: -1); | |||
} | |||
OSStatus CallHostMusicalTimeLocation(UInt32* outDeltaSampleOffsetToNextBeat, | |||
Float32* outTimeSig_Numerator, UInt32* outTimeSig_Denominator, | |||
Float64* outCurrentMeasureDownBeat) const | |||
{ | |||
return (mHostCallbackInfo.musicalTimeLocationProc != nullptr | |||
? (*mHostCallbackInfo.musicalTimeLocationProc)(mHostCallbackInfo.hostUserData, | |||
outDeltaSampleOffsetToNextBeat, outTimeSig_Numerator, | |||
outTimeSig_Denominator, outCurrentMeasureDownBeat) | |||
: -1); | |||
} | |||
OSStatus CallHostTransportState(Boolean* outIsPlaying, Boolean* outTransportStateChanged, | |||
Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, Float64* outCycleStartBeat, | |||
Float64* outCycleEndBeat) const | |||
{ | |||
return (mHostCallbackInfo.transportStateProc != nullptr | |||
? (*mHostCallbackInfo.transportStateProc)(mHostCallbackInfo.hostUserData, | |||
outIsPlaying, outTransportStateChanged, outCurrentSampleInTimeLine, | |||
outIsCycling, outCycleStartBeat, outCycleEndBeat) | |||
: -1); | |||
} | |||
[[nodiscard]] const char* GetLoggingString() const noexcept; | |||
AUMutex* GetMutex() noexcept { return mAUMutex; } | |||
// The caller of SetMutex is responsible for the managing the lifetime of the | |||
// mutex object and, if deleted before the AUBase instance, is responsible | |||
// for calling SetMutex(nullptr) | |||
void SetMutex(AUMutex* mutex) noexcept { mAUMutex = mutex; } | |||
#pragma mark - | |||
#pragma mark AU Output Base Dispatch | |||
// ________________________________________________________________________ | |||
// ________________________________________________________________________ | |||
// ________________________________________________________________________ | |||
// output unit methods | |||
virtual OSStatus Start() { return kAudio_UnimplementedError; } | |||
virtual OSStatus Stop() { return kAudio_UnimplementedError; } | |||
#pragma mark - | |||
#pragma mark AU Music Base Dispatch | |||
// ________________________________________________________________________ | |||
// ________________________________________________________________________ | |||
// ________________________________________________________________________ | |||
// music device/music effect methods | |||
virtual OSStatus MIDIEvent( | |||
UInt32 /*inStatus*/, UInt32 /*inData1*/, UInt32 /*inData2*/, UInt32 /*inOffsetSampleFrame*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
virtual OSStatus SysEx(const UInt8* /*inData*/, UInt32 /*inLength*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
#if AUSDK_MIDI2_AVAILABLE | |||
virtual OSStatus MIDIEventList( | |||
UInt32 /*inOffsetSampleFrame*/, const MIDIEventList* /*eventList*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
#endif | |||
virtual OSStatus StartNote(MusicDeviceInstrumentID /*inInstrument*/, | |||
MusicDeviceGroupID /*inGroupID*/, NoteInstanceID* /*outNoteInstanceID*/, | |||
UInt32 /*inOffsetSampleFrame*/, const MusicDeviceNoteParams& /*inParams*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
virtual OSStatus StopNote(MusicDeviceGroupID /*inGroupID*/, NoteInstanceID /*inNoteInstanceID*/, | |||
UInt32 /*inOffsetSampleFrame*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
/// Obsolete | |||
static OSStatus PrepareInstrument(MusicDeviceInstrumentID /*inInstrument*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
/// Obsolete | |||
static OSStatus ReleaseInstrument(MusicDeviceInstrumentID /*inInstrument*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
// ________________________________________________________________________ | |||
// ________________________________________________________________________ | |||
// ________________________________________________________________________ | |||
protected: | |||
#pragma mark - | |||
#pragma mark Implementation methods | |||
void PostConstructorInternal() final; | |||
void PreDestructorInternal() final; | |||
/// needs to be called when mMaxFramesPerSlice changes | |||
virtual void ReallocateBuffers(); | |||
virtual void DeallocateIOBuffers(); | |||
static void FillInParameterName( | |||
AudioUnitParameterInfo& ioInfo, CFStringRef inName, bool inShouldRelease) | |||
{ | |||
ioInfo.cfNameString = inName; | |||
ioInfo.flags |= kAudioUnitParameterFlag_HasCFNameString; | |||
if (inShouldRelease) { | |||
ioInfo.flags |= kAudioUnitParameterFlag_CFNameRelease; | |||
} | |||
CFStringGetCString(inName, &ioInfo.name[0], offsetof(AudioUnitParameterInfo, clumpID), | |||
kCFStringEncodingUTF8); | |||
} | |||
static void HasClump(AudioUnitParameterInfo& ioInfo, UInt32 inClumpID) noexcept | |||
{ | |||
ioInfo.clumpID = inClumpID; | |||
ioInfo.flags |= kAudioUnitParameterFlag_HasClump; | |||
} | |||
virtual void SetMaxFramesPerSlice(UInt32 nFrames); | |||
[[nodiscard]] virtual OSStatus CanSetMaxFrames() const; | |||
[[nodiscard]] bool WantsRenderThreadID() const noexcept { return mWantsRenderThreadID; } | |||
void SetWantsRenderThreadID(bool inFlag); | |||
OSStatus SetRenderError(OSStatus inErr) | |||
{ | |||
if (inErr != noErr && mLastRenderError == 0) { | |||
mLastRenderError = inErr; | |||
PropertyChanged(kAudioUnitProperty_LastRenderError, kAudioUnitScope_Global, 0); | |||
} | |||
return inErr; | |||
} | |||
struct PropertyListener { | |||
AudioUnitPropertyID propertyID{ 0 }; | |||
AudioUnitPropertyListenerProc listenerProc{ nullptr }; | |||
void* listenerRefCon{ nullptr }; | |||
}; | |||
using PropertyListeners = std::vector<PropertyListener>; | |||
[[nodiscard]] const PropertyListeners& GetPropertyListeners() const noexcept | |||
{ | |||
return mPropertyListeners; | |||
} | |||
HostCallbackInfo& GetHostCallbackInfo() noexcept { return mHostCallbackInfo; } | |||
private: | |||
// shared between Render and RenderSlice, inlined to minimize function call overhead | |||
OSStatus DoRenderBus(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, UInt32 inBusNumber, AUOutputElement& theOutput, | |||
UInt32 inNumberFrames, AudioBufferList& ioData) | |||
{ | |||
if (ioData.mBuffers[0].mData == nullptr || | |||
(theOutput.WillAllocateBuffer() && Outputs().GetNumberOfElements() > 1)) { | |||
// will render into cache buffer | |||
theOutput.PrepareBuffer(inNumberFrames); | |||
} else { | |||
// will render into caller's buffer | |||
theOutput.SetBufferList(ioData); | |||
} | |||
const OSStatus result = RenderBus(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames); | |||
if (result == noErr) { | |||
if (ioData.mBuffers[0].mData == nullptr) { | |||
theOutput.CopyBufferListTo(ioData); | |||
} else { | |||
theOutput.CopyBufferContentsTo(ioData); | |||
theOutput.InvalidateBufferList(); | |||
} | |||
} | |||
return result; | |||
} | |||
bool HasIcon(); | |||
[[nodiscard]] std::string CreateLoggingString() const; | |||
protected: | |||
//. Returns size. outLayoutPtr may be null if querying only for size. | |||
virtual UInt32 GetAudioChannelLayout(AudioUnitScope scope, AudioUnitElement element, | |||
AudioChannelLayout* outLayoutPtr, bool& outWritable); | |||
/// Layout is non-null. | |||
virtual OSStatus SetAudioChannelLayout( | |||
AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout); | |||
virtual OSStatus RemoveAudioChannelLayout(AudioUnitScope scope, AudioUnitElement element); | |||
virtual std::vector<AudioChannelLayoutTag> GetChannelLayoutTags( | |||
AudioUnitScope scope, AudioUnitElement element); | |||
bool NeedsToRender(const AudioTimeStamp& inTimeStamp) | |||
{ | |||
const bool needsToRender = (inTimeStamp.mSampleTime != mCurrentRenderTime.mSampleTime); | |||
if (needsToRender) { // only copy this if we need to render | |||
mCurrentRenderTime = inTimeStamp; | |||
} | |||
return needsToRender; | |||
} | |||
// Scheduled parameter implementation: | |||
using ParameterEventList = std::vector<AudioUnitParameterEvent>; | |||
// Usually, you won't override this method. You only need to call this if your DSP code | |||
// is prepared to handle scheduled immediate and ramped parameter changes. | |||
// Before calling this method, it is assumed you have already called PullInput() on the input | |||
// busses for which the DSP code depends. ProcessForScheduledParams() will call (potentially | |||
// repeatedly) virtual method ProcessScheduledSlice() to perform the actual DSP for a given | |||
// sub-division of the buffer. The job of ProcessForScheduledParams() is to sub-divide the | |||
// buffer into smaller pieces according to the scheduled times found in the ParameterEventList | |||
// (usually coming directly from a previous call to ScheduleParameter() ), setting the | |||
// appropriate immediate or ramped parameter values for the corresponding scopes and elements, | |||
// then calling ProcessScheduledSlice() to do the actual DSP for each of these divisions. | |||
virtual OSStatus ProcessForScheduledParams( | |||
ParameterEventList& inParamList, UInt32 inFramesToProcess, void* inUserData); | |||
// 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... | |||
// | |||
// sub-classes wishing to handle scheduled parameter changes should override this method | |||
// in order to do the appropriate DSP. AUEffectBase already overrides this for standard | |||
// effect AudioUnits. | |||
virtual OSStatus ProcessScheduledSlice(void* /*inUserData*/, UInt32 /*inStartFrameInBuffer*/, | |||
UInt32 /*inSliceFramesToProcess*/, UInt32 /*inTotalBufferFrames*/) | |||
{ | |||
// default implementation does nothing. | |||
return noErr; | |||
} | |||
[[nodiscard]] const AudioTimeStamp& CurrentRenderTime() const noexcept | |||
{ | |||
return mCurrentRenderTime; | |||
} | |||
void ResetRenderTime(); | |||
// ________________________________________________________________________ | |||
// Private data members to discourage hacking in subclasses | |||
private: | |||
struct RenderCallback { | |||
RenderCallback() = default; | |||
RenderCallback(AURenderCallback proc, void* ref) | |||
: mRenderNotify(proc), mRenderNotifyRefCon(ref) | |||
{ | |||
} | |||
AURenderCallback mRenderNotify = nullptr; | |||
void* mRenderNotifyRefCon = nullptr; | |||
bool operator==(const RenderCallback& other) const | |||
{ | |||
return this->mRenderNotify == other.mRenderNotify && | |||
this->mRenderNotifyRefCon == other.mRenderNotifyRefCon; | |||
} | |||
}; | |||
class RenderCallbackList { | |||
public: | |||
void add(const RenderCallback& rc) | |||
{ | |||
const std::lock_guard guard{ mLock }; | |||
const auto iter = std::find(mImpl.begin(), mImpl.end(), rc); | |||
if (iter != mImpl.end()) { | |||
return; | |||
} | |||
mImpl.emplace_back(rc); | |||
} | |||
void remove(const RenderCallback& rc) | |||
{ | |||
const std::lock_guard guard{ mLock }; | |||
const auto iter = std::find(mImpl.begin(), mImpl.end(), rc); | |||
if (iter != mImpl.end()) { | |||
mImpl.erase(iter); | |||
} | |||
} | |||
template <typename F> | |||
void foreach (F&& func) | |||
{ | |||
const std::lock_guard guard{ mLock }; | |||
for (const auto& cb : mImpl) { | |||
func(cb); | |||
} | |||
} | |||
private: | |||
AUMutex mLock; | |||
std::vector<RenderCallback> mImpl; | |||
}; | |||
protected: | |||
static constexpr AudioUnitScope kNumScopes = 4; | |||
ParameterEventList& GetParamEventList() noexcept { return mParamEventList; } | |||
void SetBuffersAllocated(bool b) noexcept { mBuffersAllocated = b; } | |||
[[nodiscard]] CFStringRef GetContextName() const { return *mContextName; } | |||
void SetContextName(CFStringRef str) { mContextName = str; } | |||
[[nodiscard]] CFStringRef GetNickName() const { return *mNickName; } | |||
private: | |||
bool mElementsCreated{ false }; | |||
bool mInitialized{ false }; | |||
bool mHasBegunInitializing{ false }; | |||
const UInt32 mInitNumInputEls; | |||
const UInt32 mInitNumOutputEls; | |||
const UInt32 mInitNumGroupEls; | |||
std::array<AUScope, kNumScopes> mScopes; | |||
RenderCallbackList mRenderCallbacks; | |||
bool mRenderCallbacksTouched{ false }; | |||
std::thread::id mRenderThreadID{}; | |||
bool mWantsRenderThreadID{ false }; | |||
AudioTimeStamp mCurrentRenderTime{}; | |||
UInt32 mMaxFramesPerSlice{ 0 }; | |||
OSStatus mLastRenderError{ noErr }; | |||
#ifndef AUSDK_NO_LOGGING | |||
const double mHostTimeFrequency{ | |||
HostTime::Frequency() | |||
}; // cache because there is calculation cost | |||
#endif | |||
AUPreset mCurrentPreset{ -1, nullptr }; | |||
bool mUsesFixedBlockSize{ false }; | |||
ParameterEventList mParamEventList; | |||
PropertyListeners mPropertyListeners; | |||
bool mBuffersAllocated{ false }; | |||
const std::string mLogString; | |||
Owned<CFStringRef> mNickName; | |||
/*! @var mAUMutex | |||
If non-null, guards all non-realtime entry points into the AudioUnit. Most AudioUnits | |||
do not need to use this. It's useful for the case of an AU which must synchronize | |||
an external source of callbacks against entry from the host. | |||
*/ | |||
AUMutex* mAUMutex{ nullptr }; | |||
HostCallbackInfo mHostCallbackInfo{}; | |||
Owned<CFStringRef> mContextName; | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUBase_h |
@@ -0,0 +1,188 @@ | |||
/*! | |||
@file AudioUnitSDK/AUBuffer.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
#include <AudioUnitSDK/AUUtility.h> | |||
namespace ausdk { | |||
inline void ThrowBadAlloc() | |||
{ | |||
AUSDK_LogError("AUBuffer throwing bad_alloc"); | |||
throw std::bad_alloc(); | |||
} | |||
// x: number to be rounded; y: the power of 2 to which to round | |||
constexpr uint32_t RoundUpToMultipleOfPowerOf2(uint32_t x, uint32_t y) noexcept | |||
{ | |||
const auto mask = y - 1; | |||
#if DEBUG | |||
assert((mask & y) == 0u); // verifies that y is a power of 2 NOLINT | |||
#endif | |||
return (x + mask) & ~mask; | |||
} | |||
// 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) { // NOLINT magic | |||
ThrowBadAlloc(); | |||
} | |||
return a * b + c; | |||
} | |||
AllocatedBuffer* BufferAllocator::Allocate( | |||
UInt32 numberBuffers, UInt32 maxBytesPerBuffer, UInt32 /*reservedFlags*/) | |||
{ | |||
constexpr size_t kAlignment = 16; | |||
constexpr size_t kMaxBufferListSize = 65536; | |||
// Check for a reasonable number of buffers (obviate a more complicated check with offsetof). | |||
if (numberBuffers > kMaxBufferListSize / sizeof(AudioBuffer)) { | |||
throw std::out_of_range("AudioBuffers::Allocate: Too many buffers"); | |||
} | |||
maxBytesPerBuffer = RoundUpToMultipleOfPowerOf2(maxBytesPerBuffer, kAlignment); | |||
const auto bufferDataSize = SafeMultiplyAddUInt32(numberBuffers, maxBytesPerBuffer, 0); | |||
void* bufferData = nullptr; | |||
if (bufferDataSize > 0) { | |||
bufferData = malloc(bufferDataSize); | |||
// don't use calloc(); it might not actually touch the memory and cause a VM fault later | |||
memset(bufferData, 0, bufferDataSize); | |||
} | |||
const auto implSize = static_cast<uint32_t>( | |||
offsetof(AllocatedBuffer, mAudioBufferList.mBuffers[std::max(UInt32(1), numberBuffers)])); | |||
auto* const implMem = malloc(implSize); | |||
auto* const allocatedBuffer = | |||
new (implMem) AllocatedBuffer{ .mMaximumNumberBuffers = numberBuffers, | |||
.mMaximumBytesPerBuffer = maxBytesPerBuffer, | |||
.mHeaderSize = implSize, | |||
.mBufferDataSize = bufferDataSize, | |||
.mBufferData = bufferData }; | |||
allocatedBuffer->mAudioBufferList.mNumberBuffers = numberBuffers; | |||
return allocatedBuffer; | |||
} | |||
void BufferAllocator::Deallocate(AllocatedBuffer* allocatedBuffer) | |||
{ | |||
if (allocatedBuffer->mBufferData != nullptr) { | |||
free(allocatedBuffer->mBufferData); | |||
} | |||
allocatedBuffer->~AllocatedBuffer(); | |||
free(allocatedBuffer); | |||
} | |||
AudioBufferList& AllocatedBuffer::Prepare(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer) | |||
{ | |||
if (mAudioBufferList.mNumberBuffers > mMaximumNumberBuffers) { | |||
throw std::out_of_range("AllocatedBuffer::Prepare(): too many buffers"); | |||
} | |||
if (bytesPerBuffer > mMaximumBytesPerBuffer) { | |||
throw std::out_of_range("AllocatedBuffer::Prepare(): insufficient capacity"); | |||
} | |||
auto* ptr = static_cast<Byte*>(mBufferData); | |||
auto* const ptrend = ptr + mBufferDataSize; | |||
for (UInt32 bufIdx = 0, nBufs = mAudioBufferList.mNumberBuffers; bufIdx < nBufs; ++bufIdx) { | |||
auto& buf = mAudioBufferList.mBuffers[bufIdx]; // NOLINT | |||
buf.mNumberChannels = channelsPerBuffer; | |||
buf.mDataByteSize = bytesPerBuffer; | |||
buf.mData = ptr; | |||
ptr += mMaximumBytesPerBuffer; // NOLINT ptr math | |||
} | |||
if (ptr > ptrend) { | |||
throw std::out_of_range("AllocatedBuffer::Prepare(): insufficient capacity"); | |||
} | |||
return mAudioBufferList; | |||
} | |||
AudioBufferList& AllocatedBuffer::PrepareNull(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer) | |||
{ | |||
if (mAudioBufferList.mNumberBuffers > mMaximumNumberBuffers) { | |||
throw std::out_of_range("AllocatedBuffer::PrepareNull(): too many buffers"); | |||
} | |||
for (UInt32 bufIdx = 0, nBufs = mAudioBufferList.mNumberBuffers; bufIdx < nBufs; ++bufIdx) { | |||
auto& buf = mAudioBufferList.mBuffers[bufIdx]; // NOLINT | |||
buf.mNumberChannels = channelsPerBuffer; | |||
buf.mDataByteSize = bytesPerBuffer; | |||
buf.mData = nullptr; | |||
} | |||
return mAudioBufferList; | |||
} | |||
AudioBufferList& AUBufferList::PrepareBuffer( | |||
const AudioStreamBasicDescription& format, UInt32 nFrames) | |||
{ | |||
ausdk::ThrowExceptionIf(nFrames > mAllocatedFrames, kAudioUnitErr_TooManyFramesToProcess); | |||
UInt32 nStreams = 0; | |||
UInt32 channelsPerStream = 0; | |||
if (ASBD::IsInterleaved(format)) { | |||
nStreams = 1; | |||
channelsPerStream = format.mChannelsPerFrame; | |||
} else { | |||
nStreams = format.mChannelsPerFrame; | |||
channelsPerStream = 1; | |||
} | |||
ausdk::ThrowExceptionIf(nStreams > mAllocatedStreams, kAudioUnitErr_FormatNotSupported); | |||
auto& abl = mBuffers->Prepare(channelsPerStream, nFrames * format.mBytesPerFrame); | |||
mPtrState = EPtrState::ToMyMemory; | |||
return abl; | |||
} | |||
AudioBufferList& AUBufferList::PrepareNullBuffer( | |||
const AudioStreamBasicDescription& format, UInt32 nFrames) | |||
{ | |||
UInt32 nStreams = 0; | |||
UInt32 channelsPerStream = 0; | |||
if (ASBD::IsInterleaved(format)) { | |||
nStreams = 1; | |||
channelsPerStream = format.mChannelsPerFrame; | |||
} else { | |||
nStreams = format.mChannelsPerFrame; | |||
channelsPerStream = 1; | |||
} | |||
ausdk::ThrowExceptionIf(nStreams > mAllocatedStreams, kAudioUnitErr_FormatNotSupported); | |||
auto& abl = mBuffers->PrepareNull(channelsPerStream, nFrames * format.mBytesPerFrame); | |||
mPtrState = EPtrState::ToExternalMemory; | |||
return abl; | |||
} | |||
void AUBufferList::Allocate(const AudioStreamBasicDescription& format, UInt32 nFrames) | |||
{ | |||
auto& alloc = BufferAllocator::instance(); | |||
if (mBuffers != nullptr) { | |||
alloc.Deallocate(mBuffers); | |||
} | |||
const uint32_t nstreams = ASBD::IsInterleaved(format) ? 1 : format.mChannelsPerFrame; | |||
mBuffers = alloc.Allocate(nstreams, nFrames * format.mBytesPerFrame, 0u); | |||
mAllocatedFrames = nFrames; | |||
mAllocatedStreams = nstreams; | |||
mPtrState = EPtrState::Invalid; | |||
} | |||
void AUBufferList::Deallocate() | |||
{ | |||
if (mBuffers != nullptr) { | |||
BufferAllocator::instance().Deallocate(mBuffers); | |||
mBuffers = nullptr; | |||
} | |||
mAllocatedFrames = 0; | |||
mAllocatedStreams = 0; | |||
mPtrState = EPtrState::Invalid; | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,166 @@ | |||
/*! | |||
@file AudioUnitSDK/AUBuffer.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUBuffer_h | |||
#define AudioUnitSDK_AUBuffer_h | |||
#include <AudioUnitSDK/AUUtility.h> | |||
#include <AudioToolbox/AudioUnit.h> | |||
#include <cstddef> | |||
#include <optional> | |||
namespace ausdk { | |||
/// struct created/destroyed by allocator. Do not attempt to manually create/destroy. | |||
struct AllocatedBuffer { | |||
const UInt32 mMaximumNumberBuffers; | |||
const UInt32 mMaximumBytesPerBuffer; | |||
const UInt32 mReservedA[2]; // NOLINT C-style array | |||
const UInt32 mHeaderSize; | |||
const UInt32 mBufferDataSize; | |||
const UInt32 mReservedB[2]; // NOLINT C-style array | |||
void* const mBufferData; | |||
void* const mReservedC; | |||
AudioBufferList mAudioBufferList; | |||
// opaque variable-length data may follow the AudioBufferList | |||
AudioBufferList& Prepare(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer); | |||
AudioBufferList& PrepareNull(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer); | |||
}; | |||
/*! | |||
@class BufferAllocator | |||
@brief Class which allocates memory for internal audio buffers. | |||
To customize, create a subclass and install an instance into the global via set_instance(). | |||
*/ | |||
class BufferAllocator { | |||
public: | |||
/// Obtain the global instance, creating it if necessary. | |||
static BufferAllocator& instance(); | |||
/// A client may install a custom global instance via this method. Throws an exception if | |||
/// a default instance has already been created. | |||
static void set_instance(BufferAllocator& instance); | |||
BufferAllocator() = default; | |||
virtual ~BufferAllocator() = default; | |||
// Rule of 5 | |||
BufferAllocator(const BufferAllocator&) = delete; | |||
BufferAllocator(BufferAllocator&&) = delete; | |||
BufferAllocator& operator=(const BufferAllocator&) = delete; | |||
BufferAllocator& operator=(BufferAllocator&&) = delete; | |||
// N.B. Must return zeroed memory aligned to at least 16 bytes. | |||
virtual AllocatedBuffer* Allocate( | |||
UInt32 numberBuffers, UInt32 maxBytesPerBuffer, UInt32 reservedFlags); | |||
virtual void Deallocate(AllocatedBuffer* allocatedBuffer); | |||
}; | |||
/*! | |||
@class AUBufferList | |||
@brief Manages an `AudioBufferList` backed by allocated memory buffers. | |||
*/ | |||
class AUBufferList { | |||
enum class EPtrState { Invalid, ToMyMemory, ToExternalMemory }; | |||
public: | |||
AUBufferList() = default; | |||
~AUBufferList() { Deallocate(); } | |||
AUBufferList(const AUBufferList&) = delete; | |||
AUBufferList(AUBufferList&&) = delete; | |||
AUBufferList& operator=(const AUBufferList&) = delete; | |||
AUBufferList& operator=(AUBufferList&&) = delete; | |||
AudioBufferList& PrepareBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames); | |||
AudioBufferList& PrepareNullBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames); | |||
AudioBufferList& SetBufferList(const AudioBufferList& abl) | |||
{ | |||
ausdk::ThrowExceptionIf(mAllocatedStreams < abl.mNumberBuffers, -1); | |||
mPtrState = EPtrState::ToExternalMemory; | |||
auto& myabl = mBuffers->mAudioBufferList; | |||
memcpy(&myabl, &abl, | |||
static_cast<size_t>( | |||
reinterpret_cast<const std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT | |||
reinterpret_cast<const std::byte*>(&abl))); // NOLINT | |||
return myabl; | |||
} | |||
void SetBuffer(UInt32 index, const AudioBuffer& ab) | |||
{ | |||
auto& myabl = mBuffers->mAudioBufferList; | |||
ausdk::ThrowExceptionIf( | |||
mPtrState == EPtrState::Invalid || index >= myabl.mNumberBuffers, -1); | |||
mPtrState = EPtrState::ToExternalMemory; | |||
myabl.mBuffers[index] = ab; // NOLINT | |||
} | |||
void InvalidateBufferList() noexcept { mPtrState = EPtrState::Invalid; } | |||
[[nodiscard]] AudioBufferList& GetBufferList() const | |||
{ | |||
ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1); | |||
return mBuffers->mAudioBufferList; | |||
} | |||
void CopyBufferListTo(AudioBufferList& abl) const | |||
{ | |||
ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1); | |||
memcpy(&abl, &mBuffers->mAudioBufferList, | |||
static_cast<size_t>( | |||
reinterpret_cast<std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT | |||
reinterpret_cast<std::byte*>(&abl))); // NOLINT | |||
} | |||
void CopyBufferContentsTo(AudioBufferList& destabl) const | |||
{ | |||
ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1); | |||
const auto& srcabl = mBuffers->mAudioBufferList; | |||
const AudioBuffer* srcbuf = srcabl.mBuffers; // NOLINT | |||
AudioBuffer* destbuf = destabl.mBuffers; // NOLINT | |||
for (UInt32 i = 0; i < destabl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) { // NOLINT | |||
if (i >= | |||
srcabl.mNumberBuffers) { // duplicate last source to additional outputs [4341137] | |||
--srcbuf; // NOLINT | |||
} | |||
if (destbuf->mData != srcbuf->mData) { | |||
memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize); | |||
} | |||
destbuf->mDataByteSize = srcbuf->mDataByteSize; | |||
} | |||
} | |||
void Allocate(const AudioStreamBasicDescription& format, UInt32 nFrames); | |||
void Deallocate(); | |||
// AudioBufferList utilities | |||
static void ZeroBuffer(AudioBufferList& abl) | |||
{ | |||
AudioBuffer* buf = abl.mBuffers; // NOLINT | |||
for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) { // NOLINT | |||
memset(buf->mData, 0, buf->mDataByteSize); | |||
} | |||
} | |||
[[nodiscard]] UInt32 GetAllocatedFrames() const noexcept { return mAllocatedFrames; } | |||
private: | |||
EPtrState mPtrState{ EPtrState::Invalid }; | |||
AllocatedBuffer* mBuffers = nullptr; // only valid between Allocate and Deallocate | |||
UInt32 mAllocatedStreams{ 0 }; | |||
UInt32 mAllocatedFrames{ 0 }; | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUBuffer_h |
@@ -0,0 +1,15 @@ | |||
/*! | |||
@file AudioUnitSDK/AUBufferAllocator.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
namespace ausdk { | |||
BufferAllocator& BufferAllocator::instance() | |||
{ | |||
__attribute__((no_destroy)) static BufferAllocator global; | |||
return global; | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,400 @@ | |||
/*! | |||
@file AudioUnitSDK/AUEffectBase.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUEffectBase.h> | |||
#include <cstddef> | |||
/* | |||
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 | |||
*/ | |||
namespace ausdk { | |||
//_____________________________________________________________________________ | |||
// | |||
AUEffectBase::AUEffectBase(AudioComponentInstance audioUnit, bool inProcessesInPlace) | |||
: AUBase(audioUnit, 1, 1), // 1 in bus, 1 out bus | |||
mProcessesInPlace(inProcessesInPlace) | |||
#if TARGET_OS_IPHONE | |||
, | |||
mOnlyOneKernel(false) | |||
#endif | |||
{ | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUEffectBase::Cleanup() | |||
{ | |||
mKernelList.clear(); | |||
mMainOutput = nullptr; | |||
mMainInput = nullptr; | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
OSStatus AUEffectBase::Initialize() | |||
{ | |||
// get our current numChannels for input and output | |||
const auto auNumInputs = static_cast<SInt16>(Input(0).GetStreamFormat().mChannelsPerFrame); | |||
const auto auNumOutputs = static_cast<SInt16>(Output(0).GetStreamFormat().mChannelsPerFrame); | |||
// does the unit publish specific information about channel configurations? | |||
const AUChannelInfo* auChannelConfigs = nullptr; | |||
const UInt32 numIOconfigs = SupportedNumChannels(&auChannelConfigs); | |||
if ((numIOconfigs > 0) && (auChannelConfigs != nullptr)) { | |||
bool foundMatch = false; | |||
for (UInt32 i = 0; (i < numIOconfigs) && !foundMatch; ++i) { | |||
const SInt16 configNumInputs = auChannelConfigs[i].inChannels; // NOLINT | |||
const SInt16 configNumOutputs = auChannelConfigs[i].outChannels; // NOLINT | |||
if ((configNumInputs < 0) && (configNumOutputs < 0)) { | |||
// unit accepts any number of channels on input and output | |||
if (((configNumInputs == -1) && (configNumOutputs == -2)) || | |||
((configNumInputs == -2) && | |||
(configNumOutputs == -1))) { // NOLINT repeated branch below | |||
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 | |||
const bool inputMatch = (auNumInputs == configNumInputs) || (configNumInputs == -1); | |||
const 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 = &Output(0); | |||
mMainInput = &Input(0); | |||
const AudioStreamBasicDescription format = GetStreamFormat(kAudioUnitScope_Output, 0); | |||
mBytesPerFrame = format.mBytesPerFrame; | |||
return noErr; | |||
} | |||
OSStatus AUEffectBase::Reset(AudioUnitScope inScope, AudioUnitElement inElement) | |||
{ | |||
for (auto& kernel : mKernelList) { | |||
if (kernel) { | |||
kernel->Reset(); | |||
} | |||
} | |||
return AUBase::Reset(inScope, inElement); | |||
} | |||
OSStatus AUEffectBase::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) | |||
{ | |||
if (inScope == kAudioUnitScope_Global) { | |||
switch (inID) { | |||
case kAudioUnitProperty_BypassEffect: | |||
case kAudioUnitProperty_InPlaceProcessing: | |||
outWritable = true; | |||
outDataSize = sizeof(UInt32); | |||
return noErr; | |||
default: | |||
break; | |||
} | |||
} | |||
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: | |||
*static_cast<UInt32*>(outData) = (IsBypassEffect() ? 1 : 0); // NOLINT | |||
return noErr; | |||
case kAudioUnitProperty_InPlaceProcessing: | |||
*static_cast<UInt32*>(outData) = (mProcessesInPlace ? 1 : 0); // NOLINT | |||
return noErr; | |||
default: | |||
break; | |||
} | |||
} | |||
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; | |||
} | |||
const bool tempNewSetting = *static_cast<const 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(kAudioUnitScope_Global, 0); | |||
} | |||
SetBypassEffect(tempNewSetting); | |||
} | |||
return noErr; | |||
} | |||
case kAudioUnitProperty_InPlaceProcessing: | |||
mProcessesInPlace = *static_cast<const UInt32*>(inData) != 0; | |||
return noErr; | |||
default: | |||
break; | |||
} | |||
} | |||
return AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize); | |||
} | |||
void AUEffectBase::MaintainKernels() | |||
{ | |||
#if TARGET_OS_IPHONE | |||
const UInt32 nKernels = mOnlyOneKernel ? 1 : GetNumberOfChannels(); | |||
#else | |||
const UInt32 nKernels = GetNumberOfChannels(); | |||
#endif | |||
if (mKernelList.size() < nKernels) { | |||
mKernelList.reserve(nKernels); | |||
for (auto i = static_cast<UInt32>(mKernelList.size()); i < nKernels; ++i) { | |||
mKernelList.push_back(NewKernel()); | |||
} | |||
} else { | |||
while (mKernelList.size() > nKernels) { | |||
mKernelList.pop_back(); | |||
} | |||
} | |||
for (UInt32 i = 0; i < nKernels; i++) { | |||
if (mKernelList[i]) { | |||
mKernelList[i]->SetChannelNum(i); | |||
} | |||
} | |||
} | |||
bool AUEffectBase::StreamFormatWritable(AudioUnitScope /*scope*/, AudioUnitElement /*element*/) | |||
{ | |||
return !IsInitialized(); | |||
} | |||
OSStatus AUEffectBase::ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement, | |||
const AudioStreamBasicDescription& inPrevFormat, const AudioStreamBasicDescription& inNewFormat) | |||
{ | |||
const 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() && | |||
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*/) | |||
{ | |||
const ScheduledProcessParams& sliceParams = *static_cast<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 (UInt32 i = 0; i < inputBufferList.mNumberBuffers; i++) { | |||
inputBufferList.mBuffers[i].mDataByteSize = // NOLINT | |||
inputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT | |||
} | |||
for (UInt32 i = 0; i < outputBufferList.mNumberBuffers; i++) { | |||
outputBufferList.mBuffers[i].mDataByteSize = // NOLINT | |||
outputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT | |||
} | |||
// process the buffer | |||
const 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 (UInt32 i = 0; i < inputBufferList.mNumberBuffers; i++) { | |||
inputBufferList.mBuffers[i].mData = // NOLINT | |||
static_cast<std::byte*>(inputBufferList.mBuffers[i].mData) + // NOLINT | |||
inputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT | |||
} | |||
for (UInt32 i = 0; i < outputBufferList.mNumberBuffers; i++) { | |||
outputBufferList.mBuffers[i].mData = // NOLINT | |||
static_cast<std::byte*>(outputBufferList.mBuffers[i].mData) + // NOLINT | |||
outputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT | |||
} | |||
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 { | |||
auto& paramEventList = GetParamEventList(); | |||
if (paramEventList.empty()) { | |||
// 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{ .actionFlags = &ioActionFlags, | |||
.inputBufferList = &inputBufferList, | |||
.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(paramEventList, nFrames, &processParams); | |||
// fixup the buffer pointers to how they were before we started | |||
const UInt32 channelSize = nFrames * mBytesPerFrame; | |||
for (UInt32 i = 0; i < inputBufferList.mNumberBuffers; i++) { | |||
const UInt32 size = | |||
inputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT | |||
inputBufferList.mBuffers[i].mData = // NOLINT | |||
static_cast<std::byte*>(inputBufferList.mBuffers[i].mData) - size; // NOLINT | |||
inputBufferList.mBuffers[i].mDataByteSize = size; // NOLINT | |||
} | |||
for (UInt32 i = 0; i < outputBufferList.mNumberBuffers; i++) { | |||
const UInt32 size = | |||
outputBufferList.mBuffers[i].mNumberChannels * channelSize; // NOLINT | |||
outputBufferList.mBuffers[i].mData = // NOLINT | |||
static_cast<std::byte*>(outputBufferList.mBuffers[i].mData) - | |||
size; // NOLINT | |||
outputBufferList.mBuffers[i].mDataByteSize = size; // NOLINT | |||
} | |||
} | |||
} | |||
if (((ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0u) && | |||
!ProcessesInPlace()) { | |||
AUBufferList::ZeroBuffer(mMainOutput->GetBufferList()); | |||
} | |||
} | |||
return result; | |||
} | |||
OSStatus AUEffectBase::ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioBufferList& inBuffer, AudioBufferList& outBuffer, UInt32 inFramesToProcess) | |||
{ | |||
if (ShouldBypassEffect()) { | |||
return noErr; | |||
} | |||
bool ioSilence = false; | |||
const bool silentInput = IsInputSilent(ioActionFlags, inFramesToProcess); | |||
ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; | |||
for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) { | |||
auto& kernel = mKernelList[channel]; | |||
if (!kernel) { | |||
continue; | |||
} | |||
ioSilence = silentInput; | |||
const AudioBuffer* const srcBuffer = &inBuffer.mBuffers[channel]; // NOLINT subscript | |||
AudioBuffer* const destBuffer = &outBuffer.mBuffers[channel]; // NOLINT subscript | |||
kernel->Process(static_cast<const Float32*>(srcBuffer->mData), | |||
static_cast<Float32*>(destBuffer->mData), inFramesToProcess, ioSilence); | |||
if (!ioSilence) { | |||
ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; | |||
} | |||
} | |||
return noErr; | |||
} | |||
Float64 AUEffectBase::GetSampleRate() { return Output(0).GetStreamFormat().mSampleRate; } | |||
UInt32 AUEffectBase::GetNumberOfChannels() { return Output(0).GetStreamFormat().mChannelsPerFrame; } | |||
} // namespace ausdk |
@@ -0,0 +1,194 @@ | |||
/*! | |||
@file AudioUnitSDK/AUEffectBase.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUEffectBase_h | |||
#define AudioUnitSDK_AUEffectBase_h | |||
#include <AudioUnitSDK/AUBase.h> | |||
#include <AudioUnitSDK/AUSilentTimeout.h> | |||
#include <memory> | |||
namespace ausdk { | |||
class AUKernelBase; | |||
/*! | |||
@class AUEffectBase | |||
@brief Base class for an effect with one input stream, one output stream, and any number of | |||
channels. | |||
*/ | |||
class AUEffectBase : public AUBase { | |||
public: | |||
explicit AUEffectBase(AudioComponentInstance audioUnit, bool inProcessesInPlace = true); | |||
AUEffectBase(const AUEffectBase&) = delete; | |||
AUEffectBase(AUEffectBase&&) = delete; | |||
AUEffectBase& operator=(const AUEffectBase&) = delete; | |||
AUEffectBase& operator=(AUEffectBase&&) = delete; | |||
~AUEffectBase() override = default; | |||
OSStatus Initialize() override; | |||
void Cleanup() override; | |||
OSStatus Reset(AudioUnitScope inScope, AudioUnitElement inElement) override; | |||
OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override; | |||
OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, void* outData) override; | |||
OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize) override; | |||
bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) override; | |||
OSStatus ChangeStreamFormat(AudioUnitScope inScope, AudioUnitElement inElement, | |||
const AudioStreamBasicDescription& inPrevFormat, | |||
const AudioStreamBasicDescription& inNewFormat) override; | |||
OSStatus Render(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, | |||
UInt32 nFrames) override; | |||
// 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. | |||
virtual std::unique_ptr<AUKernelBase> NewKernel() { return {}; } | |||
OSStatus ProcessBufferLists(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioBufferList& inBuffer, AudioBufferList& outBuffer, | |||
UInt32 inFramesToProcess) override; | |||
// convenience format accessors (use output 0's format) | |||
Float64 GetSampleRate(); | |||
UInt32 GetNumberOfChannels(); | |||
// convenience wrappers for accessing parameters in the global scope | |||
using AUBase::SetParameter; | |||
void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value) | |||
{ | |||
Globals()->SetParameter(paramID, value); | |||
} | |||
using AUBase::GetParameter; | |||
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID) | |||
{ | |||
return Globals()->GetParameter(paramID); | |||
} | |||
[[nodiscard]] bool CanScheduleParameters() const override { return true; } | |||
// This is used for the property value - to reflect to the UI if an effect is bypassed | |||
[[nodiscard]] bool IsBypassEffect() const noexcept { return mBypassEffect; } | |||
virtual void SetBypassEffect(bool inFlag) { mBypassEffect = inFlag; } | |||
void SetParamHasSampleRateDependency(bool inFlag) noexcept { mParamSRDep = inFlag; } | |||
[[nodiscard]] bool GetParamHasSampleRateDependency() const noexcept { return mParamSRDep; } | |||
/// Context, passed as `void* userData`, for `ProcessScheduledSlice()`. | |||
struct ScheduledProcessParams { | |||
AudioUnitRenderActionFlags* actionFlags = nullptr; | |||
AudioBufferList* inputBufferList = nullptr; | |||
AudioBufferList* outputBufferList = nullptr; | |||
}; | |||
OSStatus ProcessScheduledSlice(void* inUserData, UInt32 inStartFrameInBuffer, | |||
UInt32 inSliceFramesToProcess, UInt32 inTotalBufferFrames) override; | |||
[[nodiscard]] bool ProcessesInPlace() const noexcept { return mProcessesInPlace; } | |||
void SetProcessesInPlace(bool inProcessesInPlace) noexcept | |||
{ | |||
mProcessesInPlace = inProcessesInPlace; | |||
} | |||
using KernelList = std::vector<std::unique_ptr<AUKernelBase>>; | |||
protected: | |||
void MaintainKernels(); | |||
// 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(); } | |||
[[nodiscard]] AUKernelBase* GetKernel(UInt32 index) const | |||
{ | |||
return (index < mKernelList.size()) ? mKernelList[index].get() : nullptr; | |||
} | |||
[[nodiscard]] const KernelList& GetKernelList() const noexcept { return mKernelList; } | |||
bool IsInputSilent(AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess) | |||
{ | |||
bool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0; | |||
// take latency and tail time into account when propagating the silent bit | |||
const auto silentTimeoutFrames = | |||
static_cast<UInt32>(GetSampleRate() * (GetLatency() + GetTailTime())); | |||
mSilentTimeout.Process(inFramesToProcess, silentTimeoutFrames, inputSilent); | |||
return inputSilent; | |||
} | |||
#if TARGET_OS_IPHONE | |||
void SetOnlyOneKernel(bool inUseOnlyOneKernel) noexcept | |||
{ | |||
mOnlyOneKernel = inUseOnlyOneKernel; | |||
} // set in ctor of subclass that wants it. | |||
#endif | |||
private: | |||
KernelList mKernelList; | |||
bool mBypassEffect{ false }; | |||
bool mParamSRDep{ false }; | |||
bool mProcessesInPlace; | |||
AUSilentTimeout mSilentTimeout; | |||
AUOutputElement* mMainOutput{ nullptr }; | |||
AUInputElement* mMainInput{ nullptr }; | |||
#if TARGET_OS_IPHONE | |||
bool mOnlyOneKernel; | |||
#endif | |||
UInt32 mBytesPerFrame = 0; | |||
}; | |||
/*! | |||
@class AUKernelBase | |||
@brief Base class for a signal-processing "kernel", an object that performs DSP on one channel | |||
of an audio stream. | |||
*/ | |||
class AUKernelBase { | |||
public: | |||
explicit AUKernelBase(AUEffectBase& inAudioUnit) : mAudioUnit(inAudioUnit) {} | |||
AUSDK_DEPRECATED("Construct with a reference") | |||
explicit AUKernelBase(AUEffectBase* inAudioUnit) : mAudioUnit(*inAudioUnit) {} | |||
AUKernelBase(const AUKernelBase&) = delete; | |||
AUKernelBase(AUKernelBase&&) = delete; | |||
AUKernelBase& operator=(const AUKernelBase&) = delete; | |||
AUKernelBase& operator=(AUKernelBase&&) = delete; | |||
virtual ~AUKernelBase() = default; | |||
virtual void Reset() {} | |||
virtual void Process(const Float32* /*inSourceP*/, Float32* /*inDestP*/, | |||
UInt32 /*inFramesToProcess*/, bool& /*ioSilence*/) = 0; | |||
Float64 GetSampleRate() { return mAudioUnit.GetSampleRate(); } | |||
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID) | |||
{ | |||
return mAudioUnit.GetParameter(paramID); | |||
} | |||
void SetChannelNum(UInt32 inChan) noexcept { mChannelNum = inChan; } | |||
[[nodiscard]] UInt32 GetChannelNum() const noexcept { return mChannelNum; } | |||
protected: | |||
AUEffectBase& mAudioUnit; // NOLINT protected | |||
UInt32 mChannelNum = 0; // NOLINT protected | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUEffectBase_h |
@@ -0,0 +1,85 @@ | |||
/*! | |||
@file AudioUnitSDK/AUInputElement.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUBase.h> | |||
namespace ausdk { | |||
constexpr bool HasGoodBufferPointers(const AudioBufferList& abl, UInt32 nBytes) noexcept | |||
{ | |||
const AudioBuffer* buf = abl.mBuffers; // NOLINT | |||
for (UInt32 i = abl.mNumberBuffers; i-- > 0; ++buf) { // NOLINT | |||
if (buf->mData == nullptr || buf->mDataByteSize < nBytes) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
// AUInputElement::SetConnection | |||
// | |||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
void AUInputElement::SetConnection(const AudioUnitConnection& conn) | |||
{ | |||
if (conn.sourceAudioUnit == nullptr) { | |||
Disconnect(); | |||
return; | |||
} | |||
mInputType = EInputType::FromConnection; | |||
mConnection = conn; | |||
AllocateBuffer(); | |||
} | |||
void AUInputElement::Disconnect() | |||
{ | |||
mInputType = EInputType::NoInput; | |||
IOBuffer().Deallocate(); | |||
} | |||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
// AUInputElement::SetInputCallback | |||
// | |||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
void AUInputElement::SetInputCallback(AURenderCallback proc, void* refCon) | |||
{ | |||
if (proc == nullptr) { | |||
Disconnect(); | |||
} else { | |||
mInputType = EInputType::FromCallback; | |||
mInputProc = proc; | |||
mInputProcRefCon = refCon; | |||
AllocateBuffer(); | |||
} | |||
} | |||
OSStatus AUInputElement::SetStreamFormat(const AudioStreamBasicDescription& fmt) | |||
{ | |||
const OSStatus err = AUIOElement::SetStreamFormat(fmt); | |||
if (err == noErr) { | |||
AllocateBuffer(); | |||
} | |||
return err; | |||
} | |||
OSStatus AUInputElement::PullInput(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames) | |||
{ | |||
if (!IsActive()) { | |||
return kAudioUnitErr_NoConnection; | |||
} | |||
auto& iob = IOBuffer(); | |||
AudioBufferList& pullBuffer = (HasConnection() || !WillAllocateBuffer()) | |||
? iob.PrepareNullBuffer(GetStreamFormat(), nFrames) | |||
: iob.PrepareBuffer(GetStreamFormat(), nFrames); | |||
return PullInputWithBufferList(ioActionFlags, inTimeStamp, inElement, nFrames, pullBuffer); | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,91 @@ | |||
/*! | |||
@file AudioUnitSDK/AUInputElement.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUInputElement_h | |||
#define AudioUnitSDK_AUInputElement_h | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
#include <AudioUnitSDK/AUScopeElement.h> | |||
namespace ausdk { | |||
/*! | |||
@class AUInputElement | |||
@brief Implements an audio unit input element, managing the source of input from a callback | |||
or connection. | |||
*/ | |||
class AUInputElement : public AUIOElement { | |||
public: | |||
using AUIOElement::AUIOElement; | |||
// AUElement override | |||
OSStatus SetStreamFormat(const AudioStreamBasicDescription& fmt) override; | |||
[[nodiscard]] bool NeedsBufferSpace() const override { return IsCallback(); } | |||
void SetConnection(const AudioUnitConnection& conn); | |||
void SetInputCallback(AURenderCallback proc, void* refCon); | |||
[[nodiscard]] bool IsActive() const noexcept { return mInputType != EInputType::NoInput; } | |||
[[nodiscard]] bool IsCallback() const noexcept | |||
{ | |||
return mInputType == EInputType::FromCallback; | |||
} | |||
[[nodiscard]] bool HasConnection() const noexcept | |||
{ | |||
return mInputType == EInputType::FromConnection; | |||
} | |||
OSStatus PullInput(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, | |||
AudioUnitElement inElement, UInt32 nFrames); | |||
OSStatus PullInputWithBufferList(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames, | |||
AudioBufferList& inBufferList); | |||
protected: | |||
void Disconnect(); | |||
private: | |||
enum class EInputType { NoInput, FromConnection, FromCallback }; | |||
EInputType mInputType{ EInputType::NoInput }; | |||
// if from callback: | |||
AURenderCallback mInputProc{ nullptr }; | |||
void* mInputProcRefCon{ nullptr }; | |||
// if from connection: | |||
AudioUnitConnection mConnection{}; | |||
}; | |||
inline OSStatus AUInputElement::PullInputWithBufferList(AudioUnitRenderActionFlags& ioActionFlags, | |||
const AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames, | |||
AudioBufferList& inBufferList) | |||
{ | |||
OSStatus theResult = noErr; | |||
if (HasConnection()) { | |||
// only support connections for V2 audio units | |||
theResult = AudioUnitRender(mConnection.sourceAudioUnit, &ioActionFlags, &inTimeStamp, | |||
mConnection.sourceOutputNumber, nFrames, &inBufferList); | |||
} else { | |||
// kFromCallback: | |||
theResult = (mInputProc)(mInputProcRefCon, &ioActionFlags, &inTimeStamp, inElement, nFrames, | |||
&inBufferList); | |||
} | |||
if (mInputType == EInputType::NoInput) { // defense: the guy upstream could have disconnected | |||
// it's a horrible thing to do, but may happen! | |||
return kAudioUnitErr_NoConnection; | |||
} | |||
#if !TARGET_OS_IPHONE || DEBUG | |||
if (theResult == noErr) { // if there's already an error, there's no point (and maybe some harm) | |||
// in validating. | |||
if (ABL::IsBogusAudioBufferList(inBufferList) & 1) { | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
} | |||
} | |||
#endif | |||
return theResult; | |||
} | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUInputElement_h |
@@ -0,0 +1,251 @@ | |||
/*! | |||
@file AudioUnitSDK/AUMIDIBase.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUMIDIBase.h> | |||
#include <CoreMIDI/CoreMIDI.h> | |||
namespace ausdk { | |||
// MIDI CC data bytes | |||
constexpr uint8_t kMIDIController_AllSoundOff = 120u; | |||
constexpr uint8_t kMIDIController_ResetAllControllers = 121u; | |||
constexpr uint8_t kMIDIController_AllNotesOff = 123u; | |||
OSStatus AUMIDIBase::DelegateGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) | |||
{ | |||
(void)inScope; | |||
(void)inElement; | |||
(void)outDataSize; | |||
(void)outWritable; | |||
switch (inID) { // NOLINT if/else?! | |||
#if AUSDK_HAVE_XML_NAMES | |||
case kMusicDeviceProperty_MIDIXMLNames: | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
AUSDK_Require(GetXMLNames(nullptr) == noErr, kAudioUnitErr_InvalidProperty); | |||
outDataSize = sizeof(CFURLRef); | |||
outWritable = false; | |||
return noErr; | |||
#endif | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
case kAudioUnitProperty_AllParameterMIDIMappings: | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
outWritable = true; | |||
outDataSize = sizeof(AUParameterMIDIMapping) * mMIDIMapper->GetNumberMaps(); | |||
return noErr; | |||
case kAudioUnitProperty_HotMapParameterMIDIMapping: | |||
case kAudioUnitProperty_AddParameterMIDIMapping: | |||
case kAudioUnitProperty_RemoveParameterMIDIMapping: | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
outWritable = true; | |||
outDataSize = sizeof(AUParameterMIDIMapping); | |||
return noErr; | |||
#endif | |||
default: | |||
return kAudioUnitErr_InvalidProperty; | |||
} | |||
} | |||
OSStatus AUMIDIBase::DelegateGetProperty( | |||
AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData) | |||
{ | |||
(void)inScope; | |||
(void)inElement; | |||
(void)outData; | |||
switch (inID) { // NOLINT if/else?! | |||
#if AUSDK_HAVE_XML_NAMES | |||
case kMusicDeviceProperty_MIDIXMLNames: | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
return GetXMLNames(static_cast<CFURLRef*>(outData)); | |||
#endif | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
case kAudioUnitProperty_AllParameterMIDIMappings: { | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
AUParameterMIDIMapping* const maps = (static_cast<AUParameterMIDIMapping*>(outData)); | |||
mMIDIMapper->GetMaps(maps); | |||
return noErr; | |||
} | |||
case kAudioUnitProperty_HotMapParameterMIDIMapping: { | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
AUParameterMIDIMapping* const map = (static_cast<AUParameterMIDIMapping*>(outData)); | |||
mMIDIMapper->GetHotParameterMap(*map); | |||
return noErr; | |||
} | |||
#endif | |||
default: | |||
return kAudioUnitErr_InvalidProperty; | |||
} | |||
} | |||
OSStatus AUMIDIBase::DelegateSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize) | |||
{ | |||
(void)inScope; | |||
(void)inElement; | |||
(void)inData; | |||
(void)inDataSize; | |||
switch (inID) { | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
case kAudioUnitProperty_AddParameterMIDIMapping: { | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
const auto* const maps = static_cast<const AUParameterMIDIMapping*>(inData); | |||
mMIDIMapper->AddParameterMapping( | |||
maps, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance); | |||
mAUBaseInstance.PropertyChanged( | |||
kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0); | |||
return noErr; | |||
} | |||
case kAudioUnitProperty_RemoveParameterMIDIMapping: { | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
const auto* const maps = static_cast<const AUParameterMIDIMapping*>(inData); | |||
bool didChange = false; | |||
mMIDIMapper->RemoveParameterMapping( | |||
maps, (inDataSize / sizeof(AUParameterMIDIMapping)), didChange); | |||
if (didChange) { | |||
mAUBaseInstance.PropertyChanged( | |||
kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0); | |||
} | |||
return noErr; | |||
} | |||
case kAudioUnitProperty_HotMapParameterMIDIMapping: { | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
const auto& map = *static_cast<const AUParameterMIDIMapping*>(inData); | |||
mMIDIMapper->SetHotMapping(map); | |||
return noErr; | |||
} | |||
case kAudioUnitProperty_AllParameterMIDIMappings: { | |||
AUSDK_Require(mMIDIMapper, kAudioUnitErr_InvalidProperty); | |||
AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope); | |||
AUSDK_Require(inElement == 0, kAudioUnitErr_InvalidElement); | |||
const auto* const mappings = static_cast<const AUParameterMIDIMapping*>(inData); | |||
mMIDIMapper->ReplaceAllMaps( | |||
mappings, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance); | |||
return noErr; | |||
} | |||
#endif | |||
default: | |||
return kAudioUnitErr_InvalidProperty; | |||
} | |||
} | |||
constexpr uint8_t MIDIStatusNibbleValue(uint8_t status) noexcept { return (status & 0xF0U) >> 4u; } | |||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
// AUMIDIBase::HandleMIDIEvent | |||
// | |||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
OSStatus AUMIDIBase::HandleMIDIEvent( | |||
UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) | |||
{ | |||
if (!mAUBaseInstance.IsInitialized()) { | |||
return kAudioUnitErr_Uninitialized; | |||
} | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
// 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 (mMIDIMapper) { | |||
if (mMIDIMapper->HandleHotMapping(status, channel, data1, mAUBaseInstance)) { | |||
mAUBaseInstance.PropertyChanged( | |||
kAudioUnitProperty_HotMapParameterMIDIMapping, kAudioUnitScope_Global, 0); | |||
} else { | |||
mMIDIMapper->FindParameterMapEventMatch( | |||
status, channel, data1, data2, inStartFrame, mAUBaseInstance); | |||
} | |||
} | |||
#endif | |||
switch (MIDIStatusNibbleValue(status)) { | |||
case kMIDICVStatusNoteOn: | |||
if (data2 != 0u) { | |||
return HandleNoteOn(channel, data1, data2, inStartFrame); | |||
} else { | |||
// zero velocity translates to note off | |||
return HandleNoteOff(channel, data1, data2, inStartFrame); | |||
} | |||
case kMIDICVStatusNoteOff: | |||
return HandleNoteOff(channel, data1, data2, inStartFrame); | |||
default: | |||
return HandleNonNoteEvent(status, channel, data1, data2, inStartFrame); | |||
} | |||
} | |||
OSStatus AUMIDIBase::HandleNonNoteEvent( | |||
UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) | |||
{ | |||
switch (MIDIStatusNibbleValue(status)) { | |||
case kMIDICVStatusPitchBend: | |||
return HandlePitchWheel(channel, data1, data2, inStartFrame); | |||
case kMIDICVStatusProgramChange: | |||
return HandleProgramChange(channel, data1); | |||
case kMIDICVStatusChannelPressure: | |||
return HandleChannelPressure(channel, data1, inStartFrame); | |||
case kMIDICVStatusControlChange: { | |||
switch (data1) { | |||
case kMIDIController_AllNotesOff: | |||
return HandleAllNotesOff(channel); | |||
case kMIDIController_ResetAllControllers: | |||
return HandleResetAllControllers(channel); | |||
case kMIDIController_AllSoundOff: | |||
return HandleAllSoundOff(channel); | |||
default: | |||
return HandleControlChange(channel, data1, data2, inStartFrame); | |||
} | |||
} | |||
case kMIDICVStatusPolyPressure: | |||
return HandlePolyPressure(channel, data1, data2, inStartFrame); | |||
default: | |||
return noErr; | |||
} | |||
} | |||
OSStatus AUMIDIBase::SysEx(const UInt8* inData, UInt32 inLength) | |||
{ | |||
if (!mAUBaseInstance.IsInitialized()) { | |||
return kAudioUnitErr_Uninitialized; | |||
} | |||
return HandleSysEx(inData, inLength); | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,169 @@ | |||
/*! | |||
@file AudioUnitSDK/AUMIDIBase.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUMIDIBase_h | |||
#define AudioUnitSDK_AUMIDIBase_h | |||
#include <AudioUnitSDK/AUBase.h> | |||
#ifndef AUSDK_HAVE_XML_NAMES | |||
#define AUSDK_HAVE_XML_NAMES TARGET_OS_OSX // NOLINT(cppcoreguidelines-macro-usage) | |||
#endif | |||
#ifndef AUSDK_HAVE_MIDI_MAPPING | |||
#define AUSDK_HAVE_MIDI_MAPPING TARGET_OS_OSX // NOLINT(cppcoreguidelines-macro-usage) | |||
#endif | |||
namespace ausdk { | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
/// Abstract interface for parameter MIDI mapping | |||
class AUMIDIMapper { | |||
public: | |||
AUMIDIMapper() = default; | |||
virtual ~AUMIDIMapper() = default; | |||
AUMIDIMapper(const AUMIDIMapper&) = delete; | |||
AUMIDIMapper(AUMIDIMapper&&) = delete; | |||
AUMIDIMapper& operator=(const AUMIDIMapper&) = delete; | |||
AUMIDIMapper& operator=(AUMIDIMapper&&) = delete; | |||
[[nodiscard]] virtual UInt32 GetNumberMaps() const = 0; | |||
virtual void GetMaps(AUParameterMIDIMapping* outMapping) = 0; | |||
virtual void GetHotParameterMap(AUParameterMIDIMapping& outMapping) = 0; | |||
virtual void AddParameterMapping( | |||
const AUParameterMIDIMapping* maps, UInt32 count, AUBase& auBase) = 0; | |||
virtual void RemoveParameterMapping( | |||
const AUParameterMIDIMapping* maps, UInt32 count, bool& outDidChange) = 0; | |||
virtual void SetHotMapping(const AUParameterMIDIMapping& mapping) = 0; | |||
virtual void ReplaceAllMaps( | |||
const AUParameterMIDIMapping* maps, UInt32 count, AUBase& auBase) = 0; | |||
virtual bool HandleHotMapping(UInt8 status, UInt8 channel, UInt8 data1, AUBase& auBase) = 0; | |||
virtual bool FindParameterMapEventMatch(UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, | |||
UInt32 inStartFrame, AUBase& auBase) = 0; | |||
}; | |||
#endif | |||
// ________________________________________________________________________ | |||
// AUMIDIBase | |||
// | |||
/*! | |||
@class AUMIDIBase | |||
@brief Auxiliary class supporting MIDI events. | |||
*/ | |||
class AUMIDIBase { | |||
public: | |||
explicit AUMIDIBase(AUBase& inBase) : mAUBaseInstance(inBase) {} | |||
virtual ~AUMIDIBase() = default; | |||
AUMIDIBase(const AUMIDIBase&) = delete; | |||
AUMIDIBase(AUMIDIBase&&) = delete; | |||
AUMIDIBase& operator=(const AUMIDIBase&) = delete; | |||
AUMIDIBase& operator=(AUMIDIBase&&) = delete; | |||
virtual OSStatus MIDIEvent( | |||
UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame) | |||
{ | |||
const UInt32 strippedStatus = inStatus & 0xf0U; // NOLINT | |||
const UInt32 channel = inStatus & 0x0fU; // NOLINT | |||
return HandleMIDIEvent(strippedStatus, channel, inData1, inData2, inOffsetSampleFrame); | |||
} | |||
#if AUSDK_MIDI2_AVAILABLE | |||
virtual OSStatus MIDIEventList( | |||
UInt32 /*inOffsetSampleFrame*/, const MIDIEventList* /*eventList*/) | |||
{ | |||
return kAudio_UnimplementedError; | |||
} | |||
#endif | |||
virtual OSStatus SysEx(const UInt8* inData, UInt32 inLength); | |||
virtual OSStatus DelegateGetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable); | |||
virtual OSStatus DelegateGetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, void* outData); | |||
virtual OSStatus DelegateSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize); | |||
protected: | |||
// MIDI dispatch | |||
virtual OSStatus HandleMIDIEvent( | |||
UInt8 inStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame); | |||
virtual OSStatus HandleNonNoteEvent( | |||
UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame); | |||
// Old name | |||
AUSDK_DEPRECATED("HandleMIDIEvent") | |||
OSStatus HandleMidiEvent( | |||
UInt8 inStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) | |||
{ | |||
return HandleMIDIEvent(inStatus, inChannel, inData1, inData2, inStartFrame); | |||
} | |||
#if AUSDK_HAVE_XML_NAMES | |||
virtual OSStatus GetXMLNames(CFURLRef* /*outNameDocument*/) | |||
{ | |||
return kAudioUnitErr_InvalidProperty; | |||
} // if not overridden, it's unsupported | |||
#endif | |||
// channel messages | |||
virtual OSStatus HandleNoteOn( | |||
UInt8 /*inChannel*/, UInt8 /*inNoteNumber*/, UInt8 /*inVelocity*/, UInt32 /*inStartFrame*/) | |||
{ | |||
return noErr; | |||
} | |||
virtual OSStatus HandleNoteOff( | |||
UInt8 /*inChannel*/, UInt8 /*inNoteNumber*/, UInt8 /*inVelocity*/, UInt32 /*inStartFrame*/) | |||
{ | |||
return noErr; | |||
} | |||
virtual OSStatus HandleControlChange( | |||
UInt8 /*inChannel*/, UInt8 /*inController*/, UInt8 /*inValue*/, UInt32 /*inStartFrame*/) | |||
{ | |||
return noErr; | |||
} | |||
virtual OSStatus HandlePitchWheel( | |||
UInt8 /*inChannel*/, UInt8 /*inPitch1*/, UInt8 /*inPitch2*/, UInt32 /*inStartFrame*/) | |||
{ | |||
return noErr; | |||
} | |||
virtual OSStatus HandleChannelPressure( | |||
UInt8 /*inChannel*/, UInt8 /*inValue*/, UInt32 /*inStartFrame*/) | |||
{ | |||
return noErr; | |||
} | |||
virtual OSStatus HandleProgramChange(UInt8 /*inChannel*/, UInt8 /*inValue*/) { return noErr; } | |||
virtual OSStatus HandlePolyPressure( | |||
UInt8 /*inChannel*/, UInt8 /*inKey*/, UInt8 /*inValue*/, UInt32 /*inStartFrame*/) | |||
{ | |||
return noErr; | |||
} | |||
virtual OSStatus HandleResetAllControllers(UInt8 /*inChannel*/) { return noErr; } | |||
virtual OSStatus HandleAllNotesOff(UInt8 /*inChannel*/) { return noErr; } | |||
virtual OSStatus HandleAllSoundOff(UInt8 /*inChannel*/) { return noErr; } | |||
// System messages | |||
virtual OSStatus HandleSysEx(const UInt8* /*inData*/, UInt32 /*inLength*/) { return noErr; } | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
void SetMIDIMapper(const std::shared_ptr<AUMIDIMapper>& mapper) { mMIDIMapper = mapper; } | |||
#endif | |||
private: | |||
AUBase& mAUBaseInstance; | |||
#if AUSDK_HAVE_MIDI_MAPPING | |||
std::shared_ptr<AUMIDIMapper> mMIDIMapper; | |||
#endif | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUMIDIBase_h |
@@ -0,0 +1,53 @@ | |||
/*! | |||
@file AudioUnitSDK/AUMIDIEffectBase.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUMIDIEffectBase.h> | |||
namespace ausdk { | |||
AUMIDIEffectBase::AUMIDIEffectBase(AudioComponentInstance inInstance, bool inProcessesInPlace) | |||
: AUEffectBase(inInstance, inProcessesInPlace), AUMIDIBase(*static_cast<AUBase*>(this)) | |||
{ | |||
} | |||
OSStatus AUMIDIEffectBase::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) | |||
{ | |||
OSStatus 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 = 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; | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,40 @@ | |||
/*! | |||
@file AudioUnitSDK/AUMIDIEffectBase.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUMIDIEffectBase_h | |||
#define AudioUnitSDK_AUMIDIEffectBase_h | |||
#include <AudioUnitSDK/AUEffectBase.h> | |||
#include <AudioUnitSDK/AUMIDIBase.h> | |||
namespace ausdk { | |||
/*! | |||
@class AUMIDIEffectBase | |||
@brief Subclass of AUEffectBase and AUMIDIBase, providing an abstract base class for | |||
music effects. | |||
*/ | |||
class AUMIDIEffectBase : public AUEffectBase, public AUMIDIBase { | |||
public: | |||
explicit AUMIDIEffectBase(AudioComponentInstance inInstance, bool inProcessesInPlace = false); | |||
OSStatus MIDIEvent( | |||
UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame) override | |||
{ | |||
return AUMIDIBase::MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); | |||
} | |||
OSStatus SysEx(const UInt8* inData, UInt32 inLength) override | |||
{ | |||
return AUMIDIBase::SysEx(inData, inLength); | |||
} | |||
OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override; | |||
OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, void* outData) override; | |||
OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize) override; | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUMIDIEffectBase_h |
@@ -0,0 +1,20 @@ | |||
/*! | |||
@file AudioUnitSDK/AUMIDIUtility.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUMIDIUtility_h | |||
#define AudioUnitSDK_AUMIDIUtility_h | |||
// OS | |||
#if defined __has_include && __has_include(<AvailabilityVersions.h>) | |||
#include <AvailabilityVersions.h> | |||
#endif | |||
#if defined(__MAC_12_0) || defined(__IPHONE_15_0) | |||
#define AUSDK_MIDI2_AVAILABLE 1 | |||
#endif | |||
#if AUSDK_MIDI2_AVAILABLE | |||
#include <CoreMIDI/MIDIServices.h> | |||
#endif | |||
#endif // AudioUnitSDK_AUMIDIUtility_h |
@@ -0,0 +1,27 @@ | |||
/*! | |||
@file AudioUnitSDK/AUOutputElement.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUBase.h> | |||
#include <AudioUnitSDK/AUOutputElement.h> | |||
namespace ausdk { | |||
AUOutputElement::AUOutputElement(AUBase& audioUnit) : AUIOElement(audioUnit) { AllocateBuffer(); } | |||
AUOutputElement::AUOutputElement(AUBase& audioUnit, const AudioStreamBasicDescription& format) | |||
: AUIOElement{ audioUnit, format } | |||
{ | |||
AllocateBuffer(); | |||
} | |||
OSStatus AUOutputElement::SetStreamFormat(const AudioStreamBasicDescription& desc) | |||
{ | |||
const OSStatus result = AUIOElement::SetStreamFormat(desc); // inherited | |||
if (result == noErr) { | |||
AllocateBuffer(); | |||
} | |||
return result; | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,33 @@ | |||
/*! | |||
@file AudioUnitSDK/AUOutputElement.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUOutputElement_h | |||
#define AudioUnitSDK_AUOutputElement_h | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
#include <AudioUnitSDK/AUScopeElement.h> | |||
namespace ausdk { | |||
/*! | |||
@class AUOutputElement | |||
@brief Implements an audio unit output element. | |||
*/ | |||
class AUOutputElement : public AUIOElement { | |||
public: | |||
explicit AUOutputElement(AUBase& audioUnit); | |||
AUOutputElement(AUBase& audioUnit, const AudioStreamBasicDescription& format); | |||
AUSDK_DEPRECATED("Construct with a reference") | |||
explicit AUOutputElement(AUBase* audioUnit) : AUOutputElement(*audioUnit) {} | |||
// AUElement override | |||
OSStatus SetStreamFormat(const AudioStreamBasicDescription& desc) override; | |||
[[nodiscard]] bool NeedsBufferSpace() const override { return true; } | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUOutputElement_h |
@@ -0,0 +1,773 @@ | |||
/*! | |||
@file AudioUnitSDK/AUPlugInDispatch.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUBase.h> | |||
#include <AudioUnitSDK/AUPlugInDispatch.h> | |||
#include <AudioUnitSDK/AUUtility.h> | |||
#include <AudioUnitSDK/ComponentBase.h> | |||
#include <cmath> | |||
#include <cstddef> | |||
#define CATCH_EXCEPTIONS_IN_RENDER_METHODS TARGET_OS_OSX // NOLINT | |||
#define HAVE_MUSICDEVICE_PREPARE_RELEASE TARGET_OS_OSX // NOLINT | |||
namespace ausdk { | |||
// ------------------------------------------------------------------------------------------------ | |||
static auto AUInstance(void* self) | |||
{ | |||
return reinterpret_cast<AUBase*>( // NOLINT reinterpret_cast | |||
&(static_cast<AudioComponentPlugInInstance*>(self)->mInstanceStorage)); | |||
} | |||
// ------------------------------------------------------------------------------------------------ | |||
class AUInstanceGuard { | |||
public: | |||
explicit AUInstanceGuard(void* self) : mGuard(AUInstance(self)->GetMutex()) {} | |||
private: | |||
const AUEntryGuard mGuard; | |||
}; | |||
// ------------------------------------------------------------------------------------------------ | |||
static bool IsValidParameterValue(AudioUnitParameterValue value) { return std::isfinite(value); } | |||
static bool AreValidParameterEvents(const AudioUnitParameterEvent* events, UInt32 numEvents) | |||
{ | |||
if (events == nullptr) { | |||
return true; | |||
} | |||
for (UInt32 i = 0; i < numEvents; ++i) { | |||
const auto& event = events[i]; // NOLINT | |||
switch (event.eventType) { | |||
case kParameterEvent_Immediate: { | |||
if (!IsValidParameterValue(event.eventValues.immediate.value)) { // NOLINT | |||
return false; | |||
} | |||
break; | |||
} | |||
case kParameterEvent_Ramped: { | |||
if (!IsValidParameterValue(event.eventValues.ramp.startValue) || // NOLINT | |||
!IsValidParameterValue(event.eventValues.ramp.endValue)) { // NOLINT | |||
return false; | |||
} | |||
break; | |||
} | |||
default: | |||
break; | |||
} | |||
} | |||
return true; | |||
} | |||
// ------------------------------------------------------------------------------------------------ | |||
static OSStatus AUMethodInitialize(void* self) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->DoInitialize(); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodUninitialize(void* self) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
AUInstance(self)->DoCleanup(); | |||
} | |||
AUSDK_Catch(result) | |||
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. | |||
bool writable = false; | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->DispatchGetPropertyInfo(prop, scope, elem, dataSize, writable); | |||
if (outDataSize != nullptr) { | |||
*outDataSize = dataSize; | |||
} | |||
if (outWritable != nullptr) { | |||
*outWritable = static_cast<Boolean>(writable); | |||
} | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodGetProperty(void* self, AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, void* outData, UInt32* ioDataSize) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
bool writable = false; | |||
const AUInstanceGuard guard(self); | |||
if (ioDataSize == nullptr) { | |||
AUSDK_LogError("AudioUnitGetProperty: null size pointer"); | |||
return kAudio_ParamError; | |||
} | |||
if (outData == nullptr) { | |||
UInt32 dataSize = 0; | |||
result = AUInstance(self)->DispatchGetPropertyInfo( | |||
inID, inScope, inElement, dataSize, writable); | |||
*ioDataSize = dataSize; | |||
return result; | |||
} | |||
const auto clientBufferSize = *ioDataSize; | |||
if (clientBufferSize == 0) { | |||
AUSDK_LogError("AudioUnitGetProperty: *ioDataSize == 0 on entry"); | |||
return kAudio_ParamError; | |||
} | |||
UInt32 actualPropertySize = 0; | |||
result = AUInstance(self)->DispatchGetPropertyInfo( | |||
inID, inScope, inElement, actualPropertySize, writable); | |||
if (result != noErr) { | |||
return result; | |||
} | |||
std::vector<std::byte> tempBuffer; | |||
void* destBuffer = nullptr; | |||
if (clientBufferSize < actualPropertySize) { | |||
tempBuffer.resize(actualPropertySize); | |||
destBuffer = tempBuffer.data(); | |||
} else { | |||
destBuffer = outData; | |||
} | |||
result = AUInstance(self)->DispatchGetProperty(inID, inScope, inElement, destBuffer); | |||
if (result == noErr) { | |||
if (clientBufferSize < actualPropertySize && !tempBuffer.empty()) { | |||
memcpy(outData, tempBuffer.data(), clientBufferSize); | |||
// ioDataSize remains correct, the number of bytes we wrote | |||
} else { | |||
*ioDataSize = actualPropertySize; | |||
} | |||
} else { | |||
*ioDataSize = 0; | |||
} | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodSetProperty(void* self, AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
if ((inData != nullptr) && (inDataSize != 0u)) { | |||
result = | |||
AUInstance(self)->DispatchSetProperty(inID, inScope, inElement, inData, inDataSize); | |||
} else { | |||
if (inData == nullptr && inDataSize == 0) { | |||
result = AUInstance(self)->DispatchRemovePropertyValue(inID, inScope, inElement); | |||
} else { | |||
if (inData == nullptr) { | |||
AUSDK_LogError("AudioUnitSetProperty: inData == NULL"); | |||
return kAudio_ParamError; | |||
} | |||
if (inDataSize == 0) { | |||
AUSDK_LogError("AudioUnitSetProperty: inDataSize == 0"); | |||
return kAudio_ParamError; | |||
} | |||
} | |||
} | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodAddPropertyListener( | |||
void* self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void* userData) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->AddPropertyListener(prop, proc, userData); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodRemovePropertyListener( | |||
void* self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->RemovePropertyListener(prop, proc, nullptr, false); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodRemovePropertyListenerWithUserData( | |||
void* self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void* userData) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->RemovePropertyListener(prop, proc, userData, true); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodAddRenderNotify(void* self, AURenderCallback proc, void* userData) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->SetRenderNotification(proc, userData); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodRemoveRenderNotify(void* self, AURenderCallback proc, void* userData) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->RemoveRenderNotification(proc, userData); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodGetParameter(void* self, AudioUnitParameterID param, AudioUnitScope scope, | |||
AudioUnitElement elem, AudioUnitParameterValue* value) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = (value == nullptr ? kAudio_ParamError | |||
: AUInstance(self)->GetParameter(param, scope, elem, *value)); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodSetParameter(void* self, AudioUnitParameterID param, AudioUnitScope scope, | |||
AudioUnitElement elem, AudioUnitParameterValue value, UInt32 bufferOffset) | |||
{ | |||
if (!IsValidParameterValue(value)) { | |||
return kAudioUnitErr_InvalidParameterValue; | |||
} | |||
OSStatus result = noErr; | |||
try { | |||
// this is a (potentially) realtime method; no lock | |||
result = AUInstance(self)->SetParameter(param, scope, elem, value, bufferOffset); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodScheduleParameters( | |||
void* self, const AudioUnitParameterEvent* events, UInt32 numEvents) | |||
{ | |||
if (!AreValidParameterEvents(events, numEvents)) { | |||
return kAudioUnitErr_InvalidParameterValue; | |||
} | |||
OSStatus result = noErr; | |||
try { | |||
// this is a (potentially) realtime method; no lock | |||
result = AUInstance(self)->ScheduleParameter(events, numEvents); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodRender(void* self, AudioUnitRenderActionFlags* ioActionFlags, | |||
const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, | |||
AudioBufferList* ioData) | |||
{ | |||
OSStatus result = noErr; | |||
#if CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
try { | |||
#endif | |||
// this is a processing method; no lock | |||
AudioUnitRenderActionFlags tempFlags{}; | |||
if (inTimeStamp == nullptr || ioData == nullptr) { | |||
result = kAudio_ParamError; | |||
} else { | |||
if (ioActionFlags == nullptr) { | |||
tempFlags = 0; | |||
ioActionFlags = &tempFlags; | |||
} | |||
result = AUInstance(self)->DoRender( | |||
*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberFrames, *ioData); | |||
} | |||
#if CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
} | |||
AUSDK_Catch(result) | |||
#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 CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
try { | |||
#endif | |||
// this is a processing method; no lock | |||
AudioUnitRenderActionFlags tempFlags{}; | |||
if (inTimeStamp == nullptr || ioData == nullptr) { | |||
result = kAudio_ParamError; | |||
} else { | |||
if (ioActionFlags == nullptr) { | |||
tempFlags = 0; | |||
ioActionFlags = &tempFlags; | |||
} | |||
result = AUInstance(self)->ComplexRender(*ioActionFlags, *inTimeStamp, | |||
inOutputBusNumber, inNumberOfPackets, outNumberOfPackets, outPacketDescriptions, | |||
*ioData, outMetadata, outMetadataByteSize); | |||
} | |||
#if CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
} | |||
AUSDK_Catch(result) | |||
#endif | |||
return result; | |||
} | |||
static OSStatus AUMethodReset(void* self, AudioUnitScope scope, AudioUnitElement elem) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->Reset(scope, elem); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodProcess(void* self, AudioUnitRenderActionFlags* ioActionFlags, | |||
const AudioTimeStamp* inTimeStamp, UInt32 inNumberFrames, AudioBufferList* ioData) | |||
{ | |||
OSStatus result = noErr; | |||
#if CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
try { | |||
#endif | |||
// this is a processing method; no lock | |||
bool doParamCheck = true; | |||
AudioUnitRenderActionFlags tempFlags{}; | |||
if (ioActionFlags == nullptr) { | |||
tempFlags = 0; | |||
ioActionFlags = &tempFlags; | |||
} else { | |||
if ((*ioActionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs) != 0u) { | |||
doParamCheck = false; | |||
} | |||
} | |||
if (doParamCheck && (inTimeStamp == nullptr || ioData == nullptr)) { | |||
result = kAudio_ParamError; | |||
} else { | |||
result = | |||
AUInstance(self)->DoProcess(*ioActionFlags, *inTimeStamp, inNumberFrames, *ioData); | |||
} | |||
#if CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
} | |||
AUSDK_Catch(result) | |||
#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 CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
try { | |||
#endif | |||
// this is a processing method; no lock | |||
bool doParamCheck = true; | |||
AudioUnitRenderActionFlags tempFlags{}; | |||
if (ioActionFlags == nullptr) { | |||
tempFlags = 0; | |||
ioActionFlags = &tempFlags; | |||
} else { | |||
if ((*ioActionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs) != 0u) { | |||
doParamCheck = false; | |||
} | |||
} | |||
if (doParamCheck && (inTimeStamp == nullptr || inInputBufferLists == nullptr || | |||
ioOutputBufferLists == nullptr)) { | |||
result = kAudio_ParamError; | |||
} else { | |||
result = AUInstance(self)->DoProcessMultiple(*ioActionFlags, *inTimeStamp, | |||
inNumberFrames, inNumberInputBufferLists, inInputBufferLists, | |||
inNumberOutputBufferLists, ioOutputBufferLists); | |||
} | |||
#if CATCH_EXCEPTIONS_IN_RENDER_METHODS | |||
} | |||
AUSDK_Catch(result) | |||
#endif | |||
return result; | |||
} | |||
// ------------------------------------------------------------------------------------------------ | |||
static OSStatus AUMethodStart(void* self) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->Start(); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodStop(void* self) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const AUInstanceGuard guard(self); | |||
result = AUInstance(self)->Stop(); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
// ------------------------------------------------------------------------------------------------ | |||
// 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 = AUInstance(self)->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); | |||
} | |||
AUSDK_Catch(result) | |||
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 = AUInstance(self)->SysEx(inData, inLength); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
#if AUSDK_MIDI2_AVAILABLE | |||
static OSStatus AUMethodMIDIEventList( | |||
void* self, UInt32 inOffsetSampleFrame, const struct MIDIEventList* eventList) | |||
{ | |||
if (eventList == nullptr) { | |||
return kAudio_ParamError; | |||
} | |||
OSStatus result = noErr; | |||
try { | |||
// this is a potential render-time method; no lock | |||
// Note that a MIDIEventList is variably-sized and can be backed by less memory than | |||
// required, so it is Undefined Behavior to form a reference to it; we must only use | |||
// pointers. | |||
result = AUInstance(self)->MIDIEventList(inOffsetSampleFrame, eventList); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
#endif | |||
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 == nullptr) { | |||
result = kAudio_ParamError; | |||
} else { | |||
result = AUInstance(self)->StartNote( | |||
inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams); | |||
} | |||
} | |||
AUSDK_Catch(result) | |||
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 = AUInstance(self)->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame); | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
#if HAVE_MUSICDEVICE_PREPARE_RELEASE | |||
static OSStatus AUMethodPrepareInstrument(void* self, MusicDeviceInstrumentID inInstrument) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
// this is a potential render-time method; no lock | |||
result = AUInstance(self)->PrepareInstrument(inInstrument); // NOLINT static via instance | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
static OSStatus AUMethodReleaseInstrument(void* self, MusicDeviceInstrumentID inInstrument) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
// this is a potential render-time method; no lock | |||
result = AUInstance(self)->ReleaseInstrument(inInstrument); // NOLINT static via instance | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
#endif // HAVE_MUSICDEVICE_PREPARE_RELEASE | |||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
#pragma mark - | |||
#pragma mark Lookup Methods | |||
AudioComponentMethod AUBaseLookup::Lookup(SInt16 selector) | |||
{ | |||
switch (selector) { | |||
case kAudioUnitInitializeSelect: | |||
return (AudioComponentMethod)AUMethodInitialize; // NOLINT cast | |||
case kAudioUnitUninitializeSelect: | |||
return (AudioComponentMethod)AUMethodUninitialize; // NOLINT cast | |||
case kAudioUnitGetPropertyInfoSelect: | |||
return (AudioComponentMethod)AUMethodGetPropertyInfo; // NOLINT cast | |||
case kAudioUnitGetPropertySelect: | |||
return (AudioComponentMethod)AUMethodGetProperty; // NOLINT cast | |||
case kAudioUnitSetPropertySelect: | |||
return (AudioComponentMethod)AUMethodSetProperty; // NOLINT cast | |||
case kAudioUnitAddPropertyListenerSelect: | |||
return (AudioComponentMethod)AUMethodAddPropertyListener; // NOLINT cast | |||
case kAudioUnitRemovePropertyListenerSelect: | |||
return (AudioComponentMethod)AUMethodRemovePropertyListener; // NOLINT cast | |||
case kAudioUnitRemovePropertyListenerWithUserDataSelect: | |||
return (AudioComponentMethod)AUMethodRemovePropertyListenerWithUserData; // NOLINT cast | |||
case kAudioUnitAddRenderNotifySelect: | |||
return (AudioComponentMethod)AUMethodAddRenderNotify; // NOLINT cast | |||
case kAudioUnitRemoveRenderNotifySelect: | |||
return (AudioComponentMethod)AUMethodRemoveRenderNotify; // NOLINT cast | |||
case kAudioUnitGetParameterSelect: | |||
return (AudioComponentMethod)AUMethodGetParameter; // NOLINT cast | |||
case kAudioUnitSetParameterSelect: | |||
return (AudioComponentMethod)AUMethodSetParameter; // NOLINT cast | |||
case kAudioUnitScheduleParametersSelect: | |||
return (AudioComponentMethod)AUMethodScheduleParameters; // NOLINT cast | |||
case kAudioUnitRenderSelect: | |||
return (AudioComponentMethod)AUMethodRender; // NOLINT cast | |||
case kAudioUnitResetSelect: | |||
return (AudioComponentMethod)AUMethodReset; // NOLINT cast | |||
default: | |||
break; | |||
} | |||
return nullptr; | |||
} | |||
AudioComponentMethod AUOutputLookup::Lookup(SInt16 selector) | |||
{ | |||
const AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
switch (selector) { | |||
case kAudioOutputUnitStartSelect: | |||
return (AudioComponentMethod)AUMethodStart; // NOLINT cast | |||
case kAudioOutputUnitStopSelect: | |||
return (AudioComponentMethod)AUMethodStop; // NOLINT cast | |||
default: | |||
break; | |||
} | |||
return nullptr; | |||
} | |||
AudioComponentMethod AUComplexOutputLookup::Lookup(SInt16 selector) | |||
{ | |||
AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
method = AUOutputLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
if (selector == kAudioUnitComplexRenderSelect) { | |||
return (AudioComponentMethod)AUMethodComplexRender; // NOLINT cast | |||
} | |||
return nullptr; | |||
} | |||
AudioComponentMethod AUBaseProcessLookup::Lookup(SInt16 selector) | |||
{ | |||
const AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
if (selector == kAudioUnitProcessSelect) { | |||
return (AudioComponentMethod)AUMethodProcess; // NOLINT cast | |||
} | |||
return nullptr; | |||
} | |||
AudioComponentMethod AUBaseProcessMultipleLookup::Lookup(SInt16 selector) | |||
{ | |||
const AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
if (selector == kAudioUnitProcessMultipleSelect) { | |||
return (AudioComponentMethod)AUMethodProcessMultiple; // NOLINT cast | |||
} | |||
return nullptr; | |||
} | |||
AudioComponentMethod AUBaseProcessAndMultipleLookup::Lookup(SInt16 selector) | |||
{ | |||
AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
method = AUBaseProcessMultipleLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
method = AUBaseProcessLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
return nullptr; | |||
} | |||
inline AudioComponentMethod MIDI_Lookup(SInt16 selector) | |||
{ | |||
switch (selector) { | |||
case kMusicDeviceMIDIEventSelect: | |||
return (AudioComponentMethod)AUMethodMIDIEvent; // NOLINT cast | |||
case kMusicDeviceSysExSelect: | |||
return (AudioComponentMethod)AUMethodSysEx; // NOLINT cast | |||
#if AUSDK_MIDI2_AVAILABLE | |||
case kMusicDeviceMIDIEventListSelect: | |||
return (AudioComponentMethod)AUMethodMIDIEventList; // NOLINT cast | |||
#endif | |||
default: | |||
break; | |||
} | |||
return nullptr; | |||
} | |||
AudioComponentMethod AUMIDILookup::Lookup(SInt16 selector) | |||
{ | |||
const AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
return MIDI_Lookup(selector); | |||
} | |||
AudioComponentMethod AUMIDIProcessLookup::Lookup(SInt16 selector) | |||
{ | |||
const AudioComponentMethod method = AUBaseProcessLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
return MIDI_Lookup(selector); | |||
} | |||
AudioComponentMethod AUMusicLookup::Lookup(SInt16 selector) | |||
{ | |||
const AudioComponentMethod method = AUBaseLookup::Lookup(selector); | |||
if (method != nullptr) { | |||
return method; | |||
} | |||
switch (selector) { | |||
case kMusicDeviceStartNoteSelect: | |||
return (AudioComponentMethod)AUMethodStartNote; // NOLINT cast | |||
case kMusicDeviceStopNoteSelect: | |||
return (AudioComponentMethod)AUMethodStopNote; // NOLINT cast | |||
#if HAVE_MUSICDEVICE_PREPARE_RELEASE | |||
case kMusicDevicePrepareInstrumentSelect: | |||
return (AudioComponentMethod)AUMethodPrepareInstrument; // NOLINT cast | |||
case kMusicDeviceReleaseInstrumentSelect: | |||
return (AudioComponentMethod)AUMethodReleaseInstrument; // NOLINT cast | |||
#endif | |||
default: | |||
break; | |||
} | |||
return MIDI_Lookup(selector); | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,110 @@ | |||
/*! | |||
@file AudioUnitSDK/AUPlugInDispatch.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUPlugInDispatch_h | |||
#define AudioUnitSDK_AUPlugInDispatch_h | |||
#include <AudioUnitSDK/ComponentBase.h> | |||
namespace ausdk { | |||
/// Method lookup for a basic AUBase subclass. | |||
struct AUBaseLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for a basic AUBase subclass. | |||
template <class Implementor> | |||
class AUBaseFactory : public APFactory<AUBaseLookup, Implementor> { | |||
}; | |||
/// Method lookup for a AUBase subclass which implements I/O methods (Start, Stop). | |||
struct AUOutputLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements I/O methods (Start, Stop). | |||
template <class Implementor> | |||
class AUOutputBaseFactory : public APFactory<AUOutputLookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements I/O methods (Start, Stop) and | |||
/// ComplexRender. | |||
struct AUComplexOutputLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements I/O methods (Start, Stop) and ComplexRender. | |||
template <class Implementor> | |||
class AUOutputComplexBaseFactory : public APFactory<AUComplexOutputLookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements Process. | |||
struct AUBaseProcessLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements Process. | |||
template <class Implementor> | |||
class AUBaseProcessFactory : public APFactory<AUBaseProcessLookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements ProcessMultiple. | |||
struct AUBaseProcessMultipleLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements ProcessMultiple. | |||
template <class Implementor> | |||
class AUBaseProcessMultipleFactory : public APFactory<AUBaseProcessMultipleLookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements Process and ProcessMultiple. | |||
struct AUBaseProcessAndMultipleLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements Process and ProcessMultiple. | |||
template <class Implementor> | |||
class AUBaseProcessAndMultipleFactory | |||
: public APFactory<AUBaseProcessAndMultipleLookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements MusicDevice methods (MIDIEvent and SysEx). | |||
struct AUMIDILookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements MusicDevice methods (MIDIEvent and SysEx). | |||
template <class Implementor> | |||
class AUMIDIEffectFactory : public APFactory<AUMIDILookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements Process and MusicDevice methods (MIDIEvent | |||
/// and SysEx). | |||
struct AUMIDIProcessLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements Process and MusicDevice methods (MIDIEvent | |||
/// and SysEx). | |||
template <class Implementor> | |||
class AUMIDIProcessFactory : public APFactory<AUMIDIProcessLookup, Implementor> { | |||
}; | |||
/// Method lookup for an AUBase subclass which implements the full set of MusicDevice methods | |||
/// (MIDIEvent, SysEx, StartNote, StopNote). | |||
struct AUMusicLookup { | |||
static AudioComponentMethod Lookup(SInt16 selector); | |||
}; | |||
/// Factory for an AUBase subclass which implements the full set of MusicDevice methods | |||
/// (MIDIEvent, SysEx, StartNote, StopNote). | |||
template <class Implementor> | |||
class AUMusicDeviceFactory : public APFactory<AUMusicLookup, Implementor> { | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUPlugInDispatch_h |
@@ -0,0 +1,442 @@ | |||
/*! | |||
@file AudioUnitSDK/AUScopeElement.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/AUBase.h> | |||
#include <AudioUnitSDK/AUScopeElement.h> | |||
#include <AudioToolbox/AudioUnitProperties.h> | |||
#include <array> | |||
namespace ausdk { | |||
//_____________________________________________________________________________ | |||
// | |||
// By default, parameterIDs may be arbitrarily spaced, and a flat 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(UInt32 inNumberOfParameters) | |||
{ | |||
mIndexedParameters.resize(inNumberOfParameters); | |||
mUseIndexedParameters = true; | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
// Helper method. | |||
// returns whether the specified paramID is known to the element | |||
// | |||
bool AUElement::HasParameterID(AudioUnitParameterID paramID) const | |||
{ | |||
if (mUseIndexedParameters) { | |||
return paramID < mIndexedParameters.size(); | |||
} | |||
return mParameters.find(paramID) != mParameters.end(); | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
// caller assumes that this is actually an immediate parameter | |||
// | |||
AudioUnitParameterValue AUElement::GetParameter(AudioUnitParameterID paramID) const | |||
{ | |||
if (mUseIndexedParameters) { | |||
ausdk::ThrowExceptionIf( | |||
paramID >= mIndexedParameters.size(), kAudioUnitErr_InvalidParameter); | |||
return mIndexedParameters[paramID].load(std::memory_order_acquire); | |||
} | |||
const auto i = mParameters.find(paramID); | |||
ausdk::ThrowExceptionIf(i == mParameters.end(), kAudioUnitErr_InvalidParameter); | |||
return (*i).second.load(std::memory_order_acquire); | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUElement::SetParameter( | |||
AudioUnitParameterID paramID, AudioUnitParameterValue inValue, bool okWhenInitialized) | |||
{ | |||
if (mUseIndexedParameters) { | |||
ausdk::ThrowExceptionIf( | |||
paramID >= mIndexedParameters.size(), kAudioUnitErr_InvalidParameter); | |||
mIndexedParameters[paramID].store(inValue, std::memory_order_release); | |||
} else { | |||
const auto 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. | |||
// Throw(kAudioUnitErr_InvalidParameter); | |||
AUSDK_LogError( | |||
"Warning: %s SetParameter for undefined param ID %u while initialized. " | |||
"Ignoring.", | |||
mAudioUnit.GetLoggingString(), static_cast<unsigned>(paramID)); | |||
} else { | |||
// create new entry in map for the paramID (only happens first time) | |||
mParameters[paramID] = ParameterValue{ inValue }; | |||
} | |||
} else { | |||
// paramID already exists in map so simply change its value | |||
(*i).second.store(inValue, std::memory_order_release); | |||
} | |||
} | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUElement::SetScheduledEvent(AudioUnitParameterID paramID, | |||
const AudioUnitParameterEvent& inEvent, UInt32 /*inSliceOffsetInBuffer*/, | |||
UInt32 /*inSliceDurationFrames*/, bool okWhenInitialized) | |||
{ | |||
if (inEvent.eventType != kParameterEvent_Immediate) { | |||
AUSDK_LogError("Warning: %s was passed a ramped parameter event but does not implement " | |||
"them. Ignoring.", | |||
mAudioUnit.GetLoggingString()); | |||
return; | |||
} | |||
SetParameter(paramID, inEvent.eventValues.immediate.value, okWhenInitialized); // NOLINT | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUElement::GetParameterList(AudioUnitParameterID* outList) | |||
{ | |||
if (mUseIndexedParameters) { | |||
const auto nparams = static_cast<UInt32>(mIndexedParameters.size()); | |||
for (UInt32 i = 0; i < nparams; i++) { | |||
*outList++ = (AudioUnitParameterID)i; // NOLINT | |||
} | |||
} else { | |||
for (const auto& param : mParameters) { | |||
*outList++ = param.first; // NOLINT | |||
} | |||
} | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUElement::SaveState(AudioUnitScope scope, CFMutableDataRef data) | |||
{ | |||
AudioUnitParameterInfo paramInfo{}; | |||
const CFIndex countOffset = CFDataGetLength(data); | |||
uint32_t paramsWritten = 0; | |||
const auto appendBytes = [data](const void* bytes, CFIndex length) { | |||
CFDataAppendBytes(data, static_cast<const UInt8*>(bytes), length); | |||
}; | |||
const auto appendParameter = [&](AudioUnitParameterID paramID, AudioUnitParameterValue value) { | |||
struct { | |||
UInt32 paramID; | |||
UInt32 value; // really a big-endian float | |||
} entry{}; | |||
static_assert(sizeof(entry) == (sizeof(entry.paramID) + sizeof(entry.value))); | |||
if (mAudioUnit.GetParameterInfo(scope, paramID, paramInfo) == noErr) { | |||
if ((paramInfo.flags & kAudioUnitParameterFlag_CFNameRelease) != 0u) { | |||
if (paramInfo.cfNameString != nullptr) { | |||
CFRelease(paramInfo.cfNameString); | |||
} | |||
if (paramInfo.unit == kAudioUnitParameterUnit_CustomUnit && | |||
paramInfo.unitName != nullptr) { | |||
CFRelease(paramInfo.unitName); | |||
} | |||
} | |||
if (((paramInfo.flags & kAudioUnitParameterFlag_OmitFromPresets) != 0u) || | |||
((paramInfo.flags & kAudioUnitParameterFlag_MeterReadOnly) != 0u)) { | |||
return; | |||
} | |||
} | |||
entry.paramID = CFSwapInt32HostToBig(paramID); | |||
entry.value = CFSwapInt32HostToBig(*reinterpret_cast<UInt32*>(&value)); // NOLINT | |||
appendBytes(&entry, sizeof(entry)); | |||
++paramsWritten; | |||
}; | |||
constexpr UInt32 placeholderCount = 0; | |||
appendBytes(&placeholderCount, sizeof(placeholderCount)); | |||
if (mUseIndexedParameters) { | |||
const auto nparams = static_cast<UInt32>(mIndexedParameters.size()); | |||
for (UInt32 i = 0; i < nparams; i++) { | |||
appendParameter(i, mIndexedParameters[i]); | |||
} | |||
} else { | |||
for (const auto& item : mParameters) { | |||
appendParameter(item.first, item.second); | |||
} | |||
} | |||
const auto count_BE = CFSwapInt32HostToBig(paramsWritten); | |||
memcpy(CFDataGetMutableBytePtr(data) + countOffset, // NOLINT ptr math | |||
&count_BE, sizeof(count_BE)); | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
const UInt8* AUElement::RestoreState(const UInt8* state) | |||
{ | |||
union FloatInt32 { | |||
UInt32 i; | |||
AudioUnitParameterValue f; | |||
}; | |||
const UInt8* p = state; | |||
const UInt32 nparams = CFSwapInt32BigToHost(*reinterpret_cast<const UInt32*>(p)); // NOLINT | |||
p += sizeof(UInt32); // NOLINT | |||
for (UInt32 i = 0; i < nparams; ++i) { | |||
struct { | |||
AudioUnitParameterID paramID; | |||
AudioUnitParameterValue value; | |||
} entry{}; | |||
static_assert(sizeof(entry) == (sizeof(entry.paramID) + sizeof(entry.value))); | |||
entry.paramID = CFSwapInt32BigToHost(*reinterpret_cast<const UInt32*>(p)); // NOLINT | |||
p += sizeof(UInt32); // NOLINT | |||
FloatInt32 temp{}; // NOLINT | |||
temp.i = CFSwapInt32BigToHost(*reinterpret_cast<const UInt32*>(p)); // NOLINT | |||
entry.value = temp.f; // NOLINT | |||
p += sizeof(AudioUnitParameterValue); // NOLINT | |||
SetParameter(entry.paramID, entry.value); | |||
} | |||
return p; | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
AUIOElement::AUIOElement(AUBase& audioUnit) : AUElement(audioUnit), mWillAllocate(true) | |||
{ | |||
mStreamFormat = AudioStreamBasicDescription{ .mSampleRate = AUBase::kAUDefaultSampleRate, | |||
.mFormatID = kAudioFormatLinearPCM, | |||
.mFormatFlags = AudioFormatFlags(kAudioFormatFlagsNativeFloatPacked) | | |||
AudioFormatFlags(kAudioFormatFlagIsNonInterleaved), // NOLINT | |||
.mBytesPerPacket = sizeof(float), | |||
.mFramesPerPacket = 1, | |||
.mBytesPerFrame = sizeof(float), | |||
.mChannelsPerFrame = 2, | |||
.mBitsPerChannel = 32, // NOLINT | |||
.mReserved = 0 }; | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
OSStatus AUIOElement::SetStreamFormat(const AudioStreamBasicDescription& format) | |||
{ | |||
mStreamFormat = format; | |||
// Clear the previous channel layout if it is inconsistent with the newly set format; | |||
// preserve it if it is acceptable, in case the new format has no layout. | |||
if (ChannelLayout().IsValid() && NumberChannels() != ChannelLayout().NumberChannels()) { | |||
RemoveAudioChannelLayout(); | |||
} | |||
return 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(); | |||
mIOBuffer.Allocate( | |||
mStreamFormat, (mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0); | |||
} | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUIOElement::DeallocateBuffer() { mIOBuffer.Deallocate(); } | |||
//_____________________________________________________________________________ | |||
// | |||
// AudioChannelLayout support | |||
// return an empty vector (ie. NO channel layouts) if the AU doesn't require channel layout | |||
// knowledge | |||
std::vector<AudioChannelLayoutTag> AUIOElement::GetChannelLayoutTags() { return {}; } | |||
// outLayoutPtr WILL be NULL if called to determine layout size | |||
UInt32 AUIOElement::GetAudioChannelLayout(AudioChannelLayout* outLayoutPtr, bool& outWritable) | |||
{ | |||
outWritable = true; | |||
UInt32 size = mChannelLayout.IsValid() ? mChannelLayout.Size() : 0; | |||
if (size > 0 && outLayoutPtr != nullptr) { | |||
memcpy(outLayoutPtr, &mChannelLayout.Layout(), size); | |||
} | |||
return size; | |||
} | |||
// 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& inLayout) | |||
{ | |||
if (NumberChannels() != AUChannelLayout::NumberChannels(inLayout)) { | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
} | |||
mChannelLayout = inLayout; | |||
return noErr; | |||
} | |||
// 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() | |||
{ | |||
mChannelLayout = {}; | |||
return noErr; | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUScope::SetNumberOfElements(UInt32 numElements) | |||
{ | |||
if (mDelegate != nullptr) { | |||
return mDelegate->SetNumberOfElements(numElements); | |||
} | |||
if (numElements > mElements.size()) { | |||
mElements.reserve(numElements); | |||
while (numElements > mElements.size()) { | |||
auto elem = mCreator->CreateElement(GetScope(), static_cast<UInt32>(mElements.size())); | |||
mElements.push_back(std::move(elem)); | |||
} | |||
} else { | |||
while (numElements < mElements.size()) { | |||
mElements.pop_back(); | |||
} | |||
} | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
bool AUScope::HasElementWithName() const | |||
{ | |||
for (UInt32 i = 0; i < GetNumberOfElements(); ++i) { | |||
AUElement* const el = GetElement(i); | |||
if ((el != nullptr) && el->HasName()) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
void AUScope::AddElementNamesToDict(CFMutableDictionaryRef inNameDict) const | |||
{ | |||
if (HasElementWithName()) { | |||
const auto elementDict = | |||
Owned<CFMutableDictionaryRef>::from_create(CFDictionaryCreateMutable( | |||
nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); | |||
for (UInt32 i = 0; i < GetNumberOfElements(); ++i) { | |||
AUElement* const el = GetElement(i); | |||
if (el != nullptr && el->HasName()) { | |||
const auto key = Owned<CFStringRef>::from_create(CFStringCreateWithFormat( | |||
nullptr, nullptr, CFSTR("%u"), static_cast<unsigned>(i))); | |||
CFDictionarySetValue(*elementDict, *key, *el->GetName()); | |||
} | |||
} | |||
const auto key = Owned<CFStringRef>::from_create( | |||
CFStringCreateWithFormat(nullptr, nullptr, CFSTR("%u"), static_cast<unsigned>(mScope))); | |||
CFDictionarySetValue(inNameDict, *key, *elementDict); | |||
} | |||
} | |||
//_____________________________________________________________________________ | |||
// | |||
std::vector<AudioUnitElement> AUScope::RestoreElementNames(CFDictionaryRef inNameDict) const | |||
{ | |||
// first we have to see if we have enough elements | |||
std::vector<AudioUnitElement> restoredElements; | |||
const auto maxElNum = GetNumberOfElements(); | |||
const auto dictSize = | |||
static_cast<size_t>(std::max(CFDictionaryGetCount(inNameDict), CFIndex(0))); | |||
std::vector<CFStringRef> keys(dictSize); | |||
CFDictionaryGetKeysAndValues( | |||
inNameDict, reinterpret_cast<const void**>(keys.data()), nullptr); // NOLINT | |||
for (size_t i = 0; i < dictSize; i++) { | |||
unsigned int intKey = 0; | |||
std::array<char, 32> string{}; | |||
CFStringGetCString(keys[i], string.data(), string.size(), kCFStringEncodingASCII); | |||
const int result = sscanf(string.data(), "%u", &intKey); // NOLINT | |||
// check if sscanf succeeded and element index is less than max elements. | |||
if ((result != 0) && (static_cast<UInt32>(intKey) < maxElNum)) { | |||
auto* const elName = | |||
static_cast<CFStringRef>(CFDictionaryGetValue(inNameDict, keys[i])); | |||
if ((elName != nullptr) && (CFGetTypeID(elName) == CFStringGetTypeID())) { | |||
AUElement* const element = GetElement(intKey); | |||
if (element != nullptr) { | |||
element->SetName(elName); | |||
restoredElements.push_back(intKey); | |||
} | |||
} | |||
} | |||
} | |||
return restoredElements; | |||
} | |||
void AUScope::SaveState(CFMutableDataRef data) const | |||
{ | |||
const AudioUnitElement nElems = GetNumberOfElements(); | |||
for (AudioUnitElement ielem = 0; ielem < nElems; ++ielem) { | |||
AUElement* const element = GetElement(ielem); | |||
const UInt32 nparams = element->GetNumberOfParameters(); | |||
if (nparams > 0) { | |||
struct { | |||
const UInt32 scope; | |||
const UInt32 element; | |||
} hdr{ .scope = CFSwapInt32HostToBig(GetScope()), | |||
.element = CFSwapInt32HostToBig(ielem) }; | |||
static_assert(sizeof(hdr) == (sizeof(hdr.scope) + sizeof(hdr.element))); | |||
CFDataAppendBytes(data, reinterpret_cast<const UInt8*>(&hdr), sizeof(hdr)); // NOLINT | |||
element->SaveState(mScope, data); | |||
} | |||
} | |||
} | |||
const UInt8* AUScope::RestoreState(const UInt8* state) const | |||
{ | |||
const UInt8* p = state; | |||
const UInt32 elementIdx = CFSwapInt32BigToHost(*reinterpret_cast<const UInt32*>(p)); // NOLINT | |||
p += sizeof(UInt32); // NOLINT | |||
AUElement* const element = GetElement(elementIdx); | |||
if (element == nullptr) { | |||
struct { | |||
AudioUnitParameterID paramID; | |||
AudioUnitParameterValue value; | |||
} entry{}; | |||
static_assert(sizeof(entry) == (sizeof(entry.paramID) + sizeof(entry.value))); | |||
const UInt32 nparams = CFSwapInt32BigToHost(*reinterpret_cast<const UInt32*>(p)); // NOLINT | |||
p += sizeof(UInt32); // NOLINT | |||
p += nparams * sizeof(entry); // NOLINT | |||
} else { | |||
p = element->RestoreState(p); | |||
} | |||
return p; | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,435 @@ | |||
/*! | |||
@file AudioUnitSDK/AUScopeElement.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUScopeElement_h | |||
#define AudioUnitSDK_AUScopeElement_h | |||
// module | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
#include <AudioUnitSDK/AUUtility.h> | |||
#include <AudioUnitSDK/ComponentBase.h> | |||
// OS | |||
#include <AudioToolbox/AudioUnit.h> | |||
// std | |||
#include <algorithm> | |||
#include <atomic> | |||
#include <memory> | |||
#include <vector> | |||
namespace ausdk { | |||
class AUBase; | |||
/// Wrap an atomic in a copy-constructible/assignable object. This allows storing atomic values in a | |||
/// vector (not directly possible since atomics are not copy-constructible/assignable). | |||
template <typename T> | |||
class AtomicValue { | |||
public: | |||
AtomicValue() = default; | |||
explicit AtomicValue(T val) : mValue{ val } {} | |||
~AtomicValue() = default; | |||
AtomicValue(const AtomicValue& other) : mValue{ other.mValue.load() } {} | |||
AtomicValue(AtomicValue&& other) noexcept : mValue{ other.mValue.load() } {} | |||
AtomicValue& operator=(const AtomicValue& other) | |||
{ | |||
if (&other != this) { | |||
mValue.store(other.mValue.load()); | |||
} | |||
return *this; | |||
} | |||
AtomicValue& operator=(AtomicValue&& other) noexcept | |||
{ | |||
mValue.store(other.mValue.load()); | |||
return *this; | |||
} | |||
T load(std::memory_order m = std::memory_order_seq_cst) const { return mValue.load(m); } | |||
void store(T v, std::memory_order m = std::memory_order_seq_cst) { mValue.store(v, m); } | |||
operator T() const { return load(); } // NOLINT implicit conversions OK | |||
AtomicValue& operator=(T value) | |||
{ | |||
store(value); | |||
return *this; | |||
} | |||
private: | |||
std::atomic<T> mValue{}; | |||
}; | |||
/// A bare-bones reinvention of boost::flat_map, just enough to hold parameters in sorted vectors. | |||
template <typename Key, typename Value> | |||
class flat_map { | |||
using KVPair = std::pair<Key, Value>; | |||
using Impl = std::vector<std::pair<Key, Value>>; | |||
static bool keyless(const KVPair& item, Key k) { return k > item.first; } | |||
Impl mImpl; | |||
public: | |||
using iterator = typename Impl::iterator; | |||
using const_iterator = typename Impl::const_iterator; | |||
[[nodiscard]] bool empty() const { return mImpl.empty(); } | |||
[[nodiscard]] size_t size() const { return mImpl.size(); } | |||
[[nodiscard]] const_iterator begin() const { return mImpl.begin(); } | |||
[[nodiscard]] const_iterator end() const { return mImpl.end(); } | |||
iterator begin() { return mImpl.begin(); } | |||
iterator end() { return mImpl.end(); } | |||
const_iterator cbegin() { return mImpl.cbegin(); } | |||
const_iterator cend() { return mImpl.cend(); } | |||
[[nodiscard]] const_iterator lower_bound(Key k) const | |||
{ | |||
return std::lower_bound(mImpl.begin(), mImpl.end(), k, keyless); | |||
} | |||
iterator lower_bound(Key k) { return std::lower_bound(mImpl.begin(), mImpl.end(), k, keyless); } | |||
[[nodiscard]] const_iterator find(Key k) const | |||
{ | |||
auto iter = lower_bound(k); | |||
if (iter != mImpl.end()) { | |||
if ((*iter).first != k) { | |||
iter = mImpl.end(); | |||
} | |||
} | |||
return iter; | |||
} | |||
iterator find(Key k) | |||
{ | |||
auto iter = lower_bound(k); | |||
if (iter != mImpl.end()) { | |||
if ((*iter).first != k) { | |||
iter = mImpl.end(); | |||
} | |||
} | |||
return iter; | |||
} | |||
class ItemProxy { | |||
public: | |||
ItemProxy(flat_map& map, Key k) : mMap{ map }, mKey{ k } {} | |||
operator Value() const // NOLINT implicit conversion is OK | |||
{ | |||
const auto iter = mMap.find(mKey); | |||
if (iter == mMap.end()) { | |||
throw std::runtime_error("Invalid map key"); | |||
} | |||
return (*iter).second; | |||
} | |||
ItemProxy& operator=(const Value& v) | |||
{ | |||
const auto iter = mMap.lower_bound(mKey); | |||
if (iter != mMap.end() && (*iter).first == mKey) { | |||
(*iter).second = v; | |||
} else { | |||
mMap.mImpl.insert(iter, { mKey, v }); | |||
} | |||
return *this; | |||
} | |||
private: | |||
flat_map& mMap; | |||
const Key mKey; | |||
}; | |||
ItemProxy operator[](Key k) { return ItemProxy{ *this, k }; } | |||
}; | |||
// ____________________________________________________________________________ | |||
// | |||
class AUIOElement; | |||
/// An organizational unit for parameters, with a name. | |||
class AUElement { | |||
using ParameterValue = AtomicValue<float>; | |||
using ParameterMap = flat_map<AudioUnitParameterID, ParameterValue>; | |||
public: | |||
explicit AUElement(AUBase& audioUnit) : mAudioUnit(audioUnit), mUseIndexedParameters(false) {} | |||
AUSDK_DEPRECATED("Construct with a reference") | |||
explicit AUElement(AUBase* audioUnit) : AUElement(*audioUnit) {} | |||
AUElement(const AUElement&) = delete; | |||
AUElement(AUElement&&) = delete; | |||
AUElement& operator=(const AUElement&) = delete; | |||
AUElement& operator=(AUElement&&) = delete; | |||
virtual ~AUElement() = default; | |||
virtual UInt32 GetNumberOfParameters() | |||
{ | |||
return mUseIndexedParameters ? static_cast<UInt32>(mIndexedParameters.size()) | |||
: static_cast<UInt32>(mParameters.size()); | |||
} | |||
virtual void GetParameterList(AudioUnitParameterID* outList); | |||
[[nodiscard]] bool HasParameterID(AudioUnitParameterID paramID) const; | |||
[[nodiscard]] AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID) const; | |||
// Only set okWhenInitialized to true when you know the outside world cannot access this | |||
// element. Otherwise the parameter map could get corrupted. | |||
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. N.B. This only handles | |||
// immediate parameters. Override to implement ramping. Called from | |||
// AUBase::ProcessForScheduledParams. | |||
virtual void SetScheduledEvent(AudioUnitParameterID paramID, | |||
const AudioUnitParameterEvent& inEvent, UInt32 inSliceOffsetInBuffer, | |||
UInt32 inSliceDurationFrames, bool okWhenInitialized = false); | |||
[[nodiscard]] AUBase& GetAudioUnit() const noexcept { return mAudioUnit; } | |||
void SaveState(AudioUnitScope scope, CFMutableDataRef data); | |||
const UInt8* RestoreState(const UInt8* state); | |||
[[nodiscard]] Owned<CFStringRef> GetName() const { return mElementName; } | |||
void SetName(CFStringRef inName) { mElementName = inName; } | |||
[[nodiscard]] bool HasName() const { return *mElementName != nil; } | |||
virtual void UseIndexedParameters(UInt32 inNumberOfParameters); | |||
virtual AUIOElement* AsIOElement() { return nullptr; } | |||
private: | |||
// -- | |||
AUBase& mAudioUnit; | |||
ParameterMap mParameters; | |||
bool mUseIndexedParameters; | |||
std::vector<ParameterValue> mIndexedParameters; | |||
Owned<CFStringRef> mElementName; | |||
}; | |||
// ____________________________________________________________________________ | |||
// | |||
/// A subclass of AUElement which represents an input or output bus, and has an associated | |||
/// audio format and buffers. | |||
class AUIOElement : public AUElement { | |||
public: | |||
explicit AUIOElement(AUBase& audioUnit); | |||
AUIOElement(AUBase& audioUnit, const AudioStreamBasicDescription& format) | |||
: AUIOElement{ audioUnit } | |||
{ | |||
mStreamFormat = format; | |||
} | |||
AUSDK_DEPRECATED("Construct with a reference") | |||
explicit AUIOElement(AUBase* audioUnit) : AUIOElement(*audioUnit) {} | |||
[[nodiscard]] const AudioStreamBasicDescription& GetStreamFormat() const noexcept | |||
{ | |||
return mStreamFormat; | |||
} | |||
virtual OSStatus SetStreamFormat(const AudioStreamBasicDescription& format); | |||
virtual void AllocateBuffer(UInt32 inFramesToAllocate = 0); | |||
void DeallocateBuffer(); | |||
/// Determines (via subclass override) whether the element's buffer list needs to be allocated. | |||
[[nodiscard]] virtual bool NeedsBufferSpace() const = 0; | |||
void SetWillAllocateBuffer(bool inFlag) noexcept { mWillAllocate = inFlag; } | |||
[[nodiscard]] bool WillAllocateBuffer() const noexcept { return mWillAllocate; } | |||
AudioBufferList& PrepareBuffer(UInt32 nFrames) | |||
{ | |||
if (mWillAllocate) { | |||
return mIOBuffer.PrepareBuffer(mStreamFormat, nFrames); | |||
} | |||
Throw(kAudioUnitErr_InvalidPropertyValue); | |||
} | |||
AudioBufferList& PrepareNullBuffer(UInt32 nFrames) | |||
{ | |||
return mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames); | |||
} | |||
AudioBufferList& SetBufferList(AudioBufferList& abl) { return mIOBuffer.SetBufferList(abl); } | |||
void SetBuffer(UInt32 index, AudioBuffer& ab) { mIOBuffer.SetBuffer(index, ab); } | |||
void InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); } | |||
[[nodiscard]] AudioBufferList& GetBufferList() const { return mIOBuffer.GetBufferList(); } | |||
[[nodiscard]] float* GetFloat32ChannelData(UInt32 ch) | |||
{ | |||
if (IsInterleaved()) { | |||
return static_cast<float*>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; // NOLINT | |||
} | |||
return static_cast<float*>(mIOBuffer.GetBufferList().mBuffers[ch].mData); // NOLINT | |||
} | |||
void CopyBufferListTo(AudioBufferList& abl) const { mIOBuffer.CopyBufferListTo(abl); } | |||
void CopyBufferContentsTo(AudioBufferList& abl) const { mIOBuffer.CopyBufferContentsTo(abl); } | |||
[[nodiscard]] bool IsInterleaved() const noexcept { return ASBD::IsInterleaved(mStreamFormat); } | |||
[[nodiscard]] UInt32 NumberChannels() const noexcept { return mStreamFormat.mChannelsPerFrame; } | |||
[[nodiscard]] UInt32 NumberInterleavedChannels() const noexcept | |||
{ | |||
return ASBD::NumberInterleavedChannels(mStreamFormat); | |||
} | |||
virtual std::vector<AudioChannelLayoutTag> GetChannelLayoutTags(); | |||
[[nodiscard]] const AUChannelLayout& ChannelLayout() const { return mChannelLayout; } | |||
// Old layout methods | |||
virtual OSStatus SetAudioChannelLayout(const AudioChannelLayout& inLayout); | |||
virtual UInt32 GetAudioChannelLayout(AudioChannelLayout* outLayoutPtr, bool& outWritable); | |||
virtual OSStatus RemoveAudioChannelLayout(); | |||
/*! @fn AsIOElement*/ | |||
AUIOElement* AsIOElement() override { return this; } | |||
protected: | |||
AUBufferList& IOBuffer() noexcept { return mIOBuffer; } | |||
void ForceSetAudioChannelLayout(const AudioChannelLayout& inLayout) | |||
{ | |||
mChannelLayout = inLayout; | |||
} | |||
private: | |||
AudioStreamBasicDescription mStreamFormat{}; | |||
AUChannelLayout mChannelLayout{}; | |||
AUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed | |||
// for output: output cache, usually allocated early on | |||
bool mWillAllocate{ false }; | |||
}; | |||
// ____________________________________________________________________________ | |||
// | |||
/*! | |||
@class AUScopeDelegate | |||
@brief Provides a way to customize a scope, thereby obtaining virtual scopes. | |||
Can be used to implement scopes with variable numbers of elements. | |||
*/ | |||
class AUScopeDelegate { | |||
public: | |||
AUScopeDelegate() = default; | |||
virtual ~AUScopeDelegate() = default; | |||
AUScopeDelegate(const AUScopeDelegate&) = delete; | |||
AUScopeDelegate(AUScopeDelegate&&) = delete; | |||
AUScopeDelegate& operator=(const AUScopeDelegate&) = delete; | |||
AUScopeDelegate& operator=(AUScopeDelegate&&) = delete; | |||
void Initialize(AUBase* creator, AudioUnitScope scope, UInt32 numElements) | |||
{ | |||
mCreator = creator; | |||
mScope = scope; | |||
SetNumberOfElements(numElements); | |||
} | |||
virtual void SetNumberOfElements(UInt32 numElements) = 0; | |||
virtual UInt32 GetNumberOfElements() = 0; | |||
virtual AUElement* GetElement(UInt32 elementIndex) = 0; | |||
[[nodiscard]] AUBase* GetCreator() const noexcept { return mCreator; } | |||
[[nodiscard]] AudioUnitScope GetScope() const noexcept { return mScope; } | |||
private: | |||
AUBase* mCreator{ nullptr }; | |||
AudioUnitScope mScope{ 0 }; | |||
}; | |||
// ____________________________________________________________________________ | |||
// | |||
/*! | |||
@class AUScope | |||
@brief Organizes one or more elements into an addressable group (e.g. global, input, output). | |||
*/ | |||
class AUScope { | |||
public: | |||
AUScope() = default; | |||
~AUScope() = default; | |||
AUScope(const AUScope&) = delete; | |||
AUScope(AUScope&&) = delete; | |||
AUScope& operator=(const AUScope&) = delete; | |||
AUScope& operator=(AUScope&&) = delete; | |||
void Initialize(AUBase* creator, AudioUnitScope scope, UInt32 numElements) | |||
{ | |||
mCreator = creator; | |||
mScope = scope; | |||
if (mDelegate != nullptr) { | |||
return mDelegate->Initialize(creator, scope, numElements); | |||
} | |||
SetNumberOfElements(numElements); | |||
} | |||
void SetNumberOfElements(UInt32 numElements); | |||
[[nodiscard]] UInt32 GetNumberOfElements() const | |||
{ | |||
if (mDelegate != nullptr) { | |||
return mDelegate->GetNumberOfElements(); | |||
} | |||
return static_cast<UInt32>(mElements.size()); | |||
} | |||
[[nodiscard]] AUElement* GetElement(UInt32 elementIndex) const | |||
{ | |||
if (mDelegate != nullptr) { | |||
return mDelegate->GetElement(elementIndex); | |||
} | |||
return elementIndex < mElements.size() ? mElements[elementIndex].get() : nullptr; | |||
} | |||
[[nodiscard]] AUElement* SafeGetElement(UInt32 elementIndex) const | |||
{ | |||
AUElement* const element = GetElement(elementIndex); | |||
ausdk::ThrowExceptionIf(element == nullptr, kAudioUnitErr_InvalidElement); | |||
return element; | |||
} | |||
[[nodiscard]] AUIOElement* GetIOElement(UInt32 elementIndex) const | |||
{ | |||
AUElement* const element = GetElement(elementIndex); | |||
AUIOElement* const ioel = element != nullptr ? element->AsIOElement() : nullptr; | |||
ausdk::ThrowExceptionIf(ioel == nullptr, kAudioUnitErr_InvalidElement); | |||
return ioel; | |||
} | |||
[[nodiscard]] bool HasElementWithName() const; | |||
void AddElementNamesToDict(CFMutableDictionaryRef inNameDict) const; | |||
[[nodiscard]] std::vector<AudioUnitElement> RestoreElementNames( | |||
CFDictionaryRef inNameDict) const; | |||
[[nodiscard]] AudioUnitScope GetScope() const noexcept { return mScope; } | |||
void SetDelegate(AUScopeDelegate* inDelegate) noexcept { mDelegate = inDelegate; } | |||
void SaveState(CFMutableDataRef data) const; | |||
const UInt8* RestoreState(const UInt8* state) const; | |||
private: | |||
using ElementVector = std::vector<std::unique_ptr<AUElement>>; | |||
AUBase* mCreator{ nullptr }; | |||
AudioUnitScope mScope{ 0 }; | |||
ElementVector mElements; | |||
AUScopeDelegate* mDelegate{ nullptr }; | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUScopeElement_h |
@@ -0,0 +1,49 @@ | |||
/*! | |||
@file AudioUnitSDK/AUSilentTimeout.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUSilentTimeout_h | |||
#define AudioUnitSDK_AUSilentTimeout_h | |||
#include <CoreFoundation/CFBase.h> // for UInt32 | |||
#include <algorithm> | |||
namespace ausdk { | |||
/*! | |||
@class AUSilentTimeout | |||
@brief Utility to assist in propagating a silence flag from signal-processing | |||
input to output, factoring in a processing delay. | |||
*/ | |||
class AUSilentTimeout { | |||
public: | |||
AUSilentTimeout() = default; | |||
void Process(UInt32 inFramesToProcess, UInt32 inTimeoutLimit, bool& ioSilence) | |||
{ | |||
if (ioSilence) { | |||
if (mResetTimer) { | |||
mTimeoutCounter = inTimeoutLimit; | |||
mResetTimer = false; | |||
} | |||
if (mTimeoutCounter > 0) { | |||
mTimeoutCounter -= std::min(inFramesToProcess, mTimeoutCounter); | |||
ioSilence = false; | |||
} | |||
} else { | |||
// signal to reset the next time we receive silence | |||
mResetTimer = true; | |||
} | |||
} | |||
void Reset() { mResetTimer = true; } | |||
private: | |||
UInt32 mTimeoutCounter{ 0 }; | |||
bool mResetTimer{ false }; | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUSilentTimeout_h |
@@ -0,0 +1,524 @@ | |||
/*! | |||
@file AudioUnitSDK/AUUtility.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_AUUtility_h | |||
#define AudioUnitSDK_AUUtility_h | |||
// OS | |||
#if defined __has_include && __has_include(<CoreAudioTypes/CoreAudioTypes.h>) | |||
#include <CoreAudioTypes/CoreAudioTypes.h> | |||
#else | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#endif | |||
#include <libkern/OSByteOrder.h> | |||
#include <mach/mach_time.h> | |||
#include <os/log.h> | |||
#include <syslog.h> | |||
// std | |||
#include <bitset> | |||
#include <cstddef> | |||
#include <exception> | |||
#include <mutex> | |||
#include <string> | |||
#include <system_error> | |||
#include <vector> | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark General | |||
#ifdef AUSDK_NO_DEPRECATIONS | |||
#define AUSDK_DEPRECATED(msg) | |||
#else | |||
#define AUSDK_DEPRECATED(msg) [[deprecated(msg)]] // NOLINT macro | |||
#endif | |||
#ifndef AUSDK_LOG_OBJECT | |||
#define AUSDK_LOG_OBJECT OS_LOG_DEFAULT // NOLINT macro | |||
#endif | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark Version | |||
#define AUSDK_VERSION_MAJOR 1 | |||
#define AUSDK_VERSION_MINOR 1 | |||
#define AUSDK_VERSION_PATCH 0 | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark Error-handling macros | |||
#ifdef AUSDK_NO_LOGGING | |||
#define AUSDK_LogError(...) /* NOLINT macro */ | |||
#else | |||
#define AUSDK_LogError(...) /* NOLINT macro */ \ | |||
if (__builtin_available(macOS 10.11, *)) { \ | |||
os_log_error(AUSDK_LOG_OBJECT, __VA_ARGS__); \ | |||
} else { \ | |||
syslog(LOG_ERR, __VA_ARGS__); \ | |||
} | |||
#endif | |||
#define AUSDK_Catch(result) /* NOLINT(cppcoreguidelines-macro-usage) */ \ | |||
catch (const ausdk::AUException& exc) { (result) = exc.mError; } \ | |||
catch (const std::bad_alloc&) { (result) = kAudio_MemFullError; } \ | |||
catch (const OSStatus& catch_err) { (result) = catch_err; } \ | |||
catch (const std::system_error& exc) { (result) = exc.code().value(); } \ | |||
catch (...) { (result) = -1; } | |||
#define AUSDK_Require(expr, error) /* NOLINT(cppcoreguidelines-macro-usage) */ \ | |||
do { \ | |||
if (!(expr)) { \ | |||
return error; \ | |||
} \ | |||
} while (0) /* NOLINT */ | |||
#define AUSDK_Require_noerr(expr) /* NOLINT(cppcoreguidelines-macro-usage) */ \ | |||
do { \ | |||
if (const auto status_tmp_macro_detail_ = (expr); status_tmp_macro_detail_ != noErr) { \ | |||
return status_tmp_macro_detail_; \ | |||
} \ | |||
} while (0) | |||
#pragma mark - | |||
// ------------------------------------------------------------------------------------------------- | |||
namespace ausdk { | |||
// ------------------------------------------------------------------------------------------------- | |||
/// A subclass of std::runtime_error that holds an OSStatus error. | |||
class AUException : public std::runtime_error { | |||
public: | |||
explicit AUException(OSStatus err) | |||
: std::runtime_error{ std::string("OSStatus ") + std::to_string(err) }, mError{ err } | |||
{ | |||
} | |||
const OSStatus mError; | |||
}; | |||
inline void ThrowExceptionIf(bool condition, OSStatus err) | |||
{ | |||
if (condition) { | |||
AUSDK_LogError("throwing %d", static_cast<int>(err)); | |||
throw AUException{ err }; | |||
} | |||
} | |||
[[noreturn]] inline void Throw(OSStatus err) | |||
{ | |||
AUSDK_LogError("throwing %d", static_cast<int>(err)); | |||
throw AUException{ err }; | |||
} | |||
inline void ThrowQuietIf(bool condition, OSStatus err) | |||
{ | |||
if (condition) { | |||
throw AUException{ err }; | |||
} | |||
} | |||
[[noreturn]] inline void ThrowQuiet(OSStatus err) { throw AUException{ err }; } | |||
// ------------------------------------------------------------------------------------------------- | |||
/// Wrap a std::recursive_mutex in a C++ Mutex (named requirement). Methods are virtual to support | |||
/// customization. | |||
class AUMutex { | |||
public: | |||
AUMutex() = default; | |||
virtual ~AUMutex() = default; | |||
AUMutex(const AUMutex&) = delete; | |||
AUMutex(AUMutex&&) = delete; | |||
AUMutex& operator=(const AUMutex&) = delete; | |||
AUMutex& operator=(AUMutex&&) = delete; | |||
virtual void lock() { mImpl.lock(); } | |||
virtual void unlock() { mImpl.unlock(); } | |||
virtual bool try_lock() { return mImpl.try_lock(); } | |||
private: | |||
std::recursive_mutex mImpl; | |||
}; | |||
// ------------------------------------------------------------------------------------------------- | |||
/// Implement optional locking at AudioUnit non-realtime entry points (required only for a small | |||
/// number of plug-ins which must synchronize against external entry points). | |||
class AUEntryGuard { | |||
public: | |||
explicit AUEntryGuard(AUMutex* maybeMutex) : mMutex{ maybeMutex } | |||
{ | |||
if (mMutex != nullptr) { | |||
mMutex->lock(); | |||
} | |||
} | |||
~AUEntryGuard() | |||
{ | |||
if (mMutex != nullptr) { | |||
mMutex->unlock(); | |||
} | |||
} | |||
AUEntryGuard(const AUEntryGuard&) = delete; | |||
AUEntryGuard(AUEntryGuard&&) = delete; | |||
AUEntryGuard& operator=(const AUEntryGuard&) = delete; | |||
AUEntryGuard& operator=(AUEntryGuard&&) = delete; | |||
private: | |||
AUMutex* mMutex; | |||
}; | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark ASBD | |||
/// Utility functions relating to AudioStreamBasicDescription. | |||
namespace ASBD { | |||
constexpr bool IsInterleaved(const AudioStreamBasicDescription& format) noexcept | |||
{ | |||
return (format.mFormatFlags & kLinearPCMFormatFlagIsNonInterleaved) == 0u; | |||
} | |||
constexpr UInt32 NumberInterleavedChannels(const AudioStreamBasicDescription& format) noexcept | |||
{ | |||
return IsInterleaved(format) ? format.mChannelsPerFrame : 1; | |||
} | |||
constexpr UInt32 NumberChannelStreams(const AudioStreamBasicDescription& format) noexcept | |||
{ | |||
return IsInterleaved(format) ? 1 : format.mChannelsPerFrame; | |||
} | |||
constexpr bool IsCommonFloat32(const AudioStreamBasicDescription& format) noexcept | |||
{ | |||
return ( | |||
format.mFormatID == kAudioFormatLinearPCM && format.mFramesPerPacket == 1 && | |||
format.mBytesPerPacket == format.mBytesPerFrame | |||
// so far, it's a valid PCM format | |||
&& (format.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0 && | |||
(format.mChannelsPerFrame == 1 || | |||
(format.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) && | |||
((format.mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian) && | |||
format.mBitsPerChannel == 32 // NOLINT | |||
&& format.mBytesPerFrame == NumberInterleavedChannels(format) * sizeof(float)); | |||
} | |||
constexpr AudioStreamBasicDescription CreateCommonFloat32( | |||
Float64 sampleRate, UInt32 numChannels, bool interleaved = false) noexcept | |||
{ | |||
constexpr auto sampleSize = sizeof(Float32); | |||
AudioStreamBasicDescription asbd{}; | |||
asbd.mFormatID = kAudioFormatLinearPCM; | |||
asbd.mFormatFlags = kAudioFormatFlagIsFloat | | |||
static_cast<AudioFormatFlags>(kAudioFormatFlagsNativeEndian) | | |||
kAudioFormatFlagIsPacked; | |||
asbd.mBitsPerChannel = 8 * sampleSize; // NOLINT magic number | |||
asbd.mChannelsPerFrame = numChannels; | |||
asbd.mFramesPerPacket = 1; | |||
asbd.mSampleRate = sampleRate; | |||
if (interleaved) { | |||
asbd.mBytesPerPacket = asbd.mBytesPerFrame = numChannels * sampleSize; | |||
} else { | |||
asbd.mBytesPerPacket = asbd.mBytesPerFrame = sampleSize; | |||
asbd.mFormatFlags |= kAudioFormatFlagIsNonInterleaved; | |||
} | |||
return asbd; | |||
} | |||
constexpr bool MinimalSafetyCheck(const AudioStreamBasicDescription& x) noexcept | |||
{ | |||
// This function returns false if there are sufficiently unreasonable values in any field. | |||
// It is very conservative so even some very unlikely values will pass. | |||
// This is just meant to catch the case where the data from a file is corrupted. | |||
return (x.mSampleRate >= 0.) && (x.mSampleRate < 3e6) // NOLINT SACD sample rate is 2.8224 MHz | |||
&& (x.mBytesPerPacket < 1000000) // NOLINT | |||
&& (x.mFramesPerPacket < 1000000) // NOLINT | |||
&& (x.mBytesPerFrame < 1000000) // NOLINT | |||
&& (x.mChannelsPerFrame > 0) && (x.mChannelsPerFrame <= 1024) // NOLINT | |||
&& (x.mBitsPerChannel <= 1024) // NOLINT | |||
&& (x.mFormatID != 0) && | |||
!(x.mFormatID == kAudioFormatLinearPCM && | |||
(x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame)); | |||
} | |||
inline bool IsEqual( | |||
const AudioStreamBasicDescription& lhs, const AudioStreamBasicDescription& rhs) noexcept | |||
{ | |||
return memcmp(&lhs, &rhs, sizeof(AudioStreamBasicDescription)) == 0; | |||
} | |||
} // namespace ASBD | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark ACL | |||
/// Utility functions relating to AudioChannelLayout. | |||
namespace ACL { | |||
constexpr bool operator==(const AudioChannelLayout& lhs, const AudioChannelLayout& rhs) noexcept | |||
{ | |||
if (lhs.mChannelLayoutTag != rhs.mChannelLayoutTag) { | |||
return false; | |||
} | |||
if (lhs.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { | |||
return lhs.mChannelBitmap == rhs.mChannelBitmap; | |||
} | |||
if (lhs.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { | |||
if (lhs.mNumberChannelDescriptions != rhs.mNumberChannelDescriptions) { | |||
return false; | |||
} | |||
for (auto i = 0u; i < lhs.mNumberChannelDescriptions; ++i) { | |||
const auto& lhdesc = lhs.mChannelDescriptions[i]; // NOLINT array subscript | |||
const auto& rhdesc = rhs.mChannelDescriptions[i]; // NOLINT array subscript | |||
if (lhdesc.mChannelLabel != rhdesc.mChannelLabel) { | |||
return false; | |||
} | |||
if (lhdesc.mChannelLabel == kAudioChannelLabel_UseCoordinates) { | |||
if (memcmp(&lhdesc, &rhdesc, sizeof(AudioChannelDescription)) != 0) { | |||
return false; | |||
} | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
} // namespace ACL | |||
// ------------------------------------------------------------------------------------------------- | |||
/// Utility wrapper for the variably-sized AudioChannelLayout struct. | |||
class AUChannelLayout { | |||
public: | |||
AUChannelLayout() : AUChannelLayout(0, kAudioChannelLayoutTag_UseChannelDescriptions, 0) {} | |||
/// Can construct from a layout tag. | |||
explicit AUChannelLayout(AudioChannelLayoutTag inTag) : AUChannelLayout(0, inTag, 0) {} | |||
AUChannelLayout(uint32_t inNumberChannelDescriptions, AudioChannelLayoutTag inChannelLayoutTag, | |||
AudioChannelBitmap inChannelBitMap) | |||
: mStorage( | |||
kHeaderSize + (inNumberChannelDescriptions * sizeof(AudioChannelDescription)), {}) | |||
{ | |||
auto* const acl = reinterpret_cast<AudioChannelLayout*>(mStorage.data()); // NOLINT | |||
acl->mChannelLayoutTag = inChannelLayoutTag; | |||
acl->mChannelBitmap = inChannelBitMap; | |||
acl->mNumberChannelDescriptions = inNumberChannelDescriptions; | |||
} | |||
/// Implicit conversion from AudioChannelLayout& is allowed. | |||
AUChannelLayout(const AudioChannelLayout& acl) // NOLINT | |||
: mStorage(kHeaderSize + (acl.mNumberChannelDescriptions * sizeof(AudioChannelDescription))) | |||
{ | |||
memcpy(mStorage.data(), &acl, mStorage.size()); | |||
} | |||
bool operator==(const AUChannelLayout& other) const noexcept | |||
{ | |||
return ACL::operator==(Layout(), other.Layout()); | |||
} | |||
bool operator!=(const AUChannelLayout& y) const noexcept { return !(*this == y); } | |||
[[nodiscard]] bool IsValid() const noexcept { return NumberChannels() > 0; } | |||
[[nodiscard]] const AudioChannelLayout& Layout() const noexcept { return *LayoutPtr(); } | |||
[[nodiscard]] const AudioChannelLayout* LayoutPtr() const noexcept | |||
{ | |||
return reinterpret_cast<const AudioChannelLayout*>(mStorage.data()); // NOLINT | |||
} | |||
/// After default construction, this method will return | |||
/// kAudioChannelLayoutTag_UseChannelDescriptions with 0 channel descriptions. | |||
[[nodiscard]] AudioChannelLayoutTag Tag() const noexcept { return Layout().mChannelLayoutTag; } | |||
[[nodiscard]] uint32_t NumberChannels() const noexcept { return NumberChannels(*LayoutPtr()); } | |||
[[nodiscard]] uint32_t Size() const noexcept { return static_cast<uint32_t>(mStorage.size()); } | |||
static uint32_t NumberChannels(const AudioChannelLayout& inLayout) noexcept | |||
{ | |||
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { | |||
return inLayout.mNumberChannelDescriptions; | |||
} | |||
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { | |||
return static_cast<uint32_t>( | |||
std::bitset<32>(inLayout.mChannelBitmap).count()); // NOLINT magic # | |||
} | |||
return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag); | |||
} | |||
private: | |||
constexpr static size_t kHeaderSize = offsetof(AudioChannelLayout, mChannelDescriptions[0]); | |||
std::vector<std::byte> mStorage; | |||
}; | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark AudioBufferList | |||
/// Utility functions relating to AudioBufferList. | |||
namespace ABL { | |||
// if the return result is odd, there was a null buffer. | |||
inline uint32_t IsBogusAudioBufferList(const AudioBufferList& abl) | |||
{ | |||
const AudioBuffer *buf = abl.mBuffers, *const bufEnd = buf + abl.mNumberBuffers; | |||
uint32_t sum = | |||
0; // defeat attempts by the compiler to optimize away the code that touches the buffers | |||
uint32_t anyNull = 0; | |||
for (; buf < bufEnd; ++buf) { | |||
const uint32_t* const p = static_cast<const uint32_t*>(buf->mData); | |||
if (p == nullptr) { | |||
anyNull = 1; | |||
continue; | |||
} | |||
const auto dataSize = buf->mDataByteSize; | |||
if (dataSize >= sizeof(*p)) { | |||
const size_t frameCount = dataSize / sizeof(*p); | |||
sum += p[0]; | |||
sum += p[frameCount - 1]; | |||
} | |||
} | |||
return anyNull | (sum & ~1u); | |||
} | |||
} // namespace ABL | |||
// ------------------------------------------------------------------------------------------------- | |||
#pragma mark - | |||
#pragma mark HostTime | |||
/// Utility functions relating to Mach absolute time. | |||
namespace HostTime { | |||
/// Returns the current host time | |||
inline uint64_t Current() { return mach_absolute_time(); } | |||
/// Returns the frequency of the host timebase, in ticks per second. | |||
inline double Frequency() | |||
{ | |||
struct mach_timebase_info timeBaseInfo { | |||
}; // NOLINT | |||
mach_timebase_info(&timeBaseInfo); | |||
// the frequency of that clock is: (sToNanosDenominator / sToNanosNumerator) * 10^9 | |||
return static_cast<double>(timeBaseInfo.denom) / static_cast<double>(timeBaseInfo.numer) * | |||
1.0e9; // NOLINT | |||
} | |||
} // namespace HostTime | |||
// ------------------------------------------------------------------------------------------------- | |||
/// Basic RAII wrapper for CoreFoundation types | |||
template <typename T> | |||
class Owned { | |||
explicit Owned(T obj, bool fromget) noexcept : mImpl{ obj } | |||
{ | |||
if (fromget) { | |||
retainRef(); | |||
} | |||
} | |||
public: | |||
static Owned from_get(T obj) noexcept { return Owned{ obj, true }; } | |||
static Owned from_create(T obj) noexcept { return Owned{ obj, false }; } | |||
static Owned from_copy(T obj) noexcept { return Owned{ obj, false }; } | |||
Owned() noexcept = default; | |||
~Owned() noexcept { releaseRef(); } | |||
Owned(const Owned& other) noexcept : mImpl{ other.mImpl } { retainRef(); } | |||
Owned(Owned&& other) noexcept : mImpl{ std::exchange(other.mImpl, nullptr) } {} | |||
Owned& operator=(const Owned& other) noexcept | |||
{ | |||
if (this != &other) { | |||
releaseRef(); | |||
mImpl = other.mImpl; | |||
retainRef(); | |||
} | |||
return *this; | |||
} | |||
Owned& operator=(Owned&& other) noexcept | |||
{ | |||
std::swap(mImpl, other.mImpl); | |||
return *this; | |||
} | |||
T operator*() const noexcept { return get(); } | |||
T get() const noexcept { return mImpl; } | |||
/// As with `unique_ptr<T>::release()`, releases ownership of the reference to the caller (not | |||
/// to be confused with decrementing the reference count as with `CFRelease()`). | |||
T release() noexcept { return std::exchange(mImpl, nullptr); } | |||
/// This is a from_get operation. | |||
Owned& operator=(T cfobj) noexcept | |||
{ | |||
if (mImpl != cfobj) { | |||
releaseRef(); | |||
mImpl = cfobj; | |||
retainRef(); | |||
} | |||
return *this; | |||
} | |||
private: | |||
void retainRef() noexcept | |||
{ | |||
if (mImpl != nullptr) { | |||
CFRetain(mImpl); | |||
} | |||
} | |||
void releaseRef() noexcept | |||
{ | |||
if (mImpl != nullptr) { | |||
CFRelease(mImpl); | |||
} | |||
} | |||
T mImpl{ nullptr }; | |||
}; | |||
// ------------------------------------------------------------------------------------------------- | |||
constexpr bool safe_isprint(char in_char) noexcept { return (in_char >= ' ') && (in_char <= '~'); } | |||
inline std::string make_string_from_4cc(uint32_t in_4cc) noexcept | |||
{ | |||
#if !TARGET_RT_BIG_ENDIAN | |||
in_4cc = OSSwapInt32(in_4cc); // NOLINT | |||
#endif | |||
char* const string = reinterpret_cast<char*>(&in_4cc); // NOLINT | |||
for (size_t i = 0; i < sizeof(in_4cc); ++i) { | |||
if (!safe_isprint(string[i])) { // NOLINT | |||
string[i] = '.'; // NOLINT | |||
} | |||
} | |||
return std::string{ string, sizeof(in_4cc) }; | |||
} | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_AUUtility_h |
@@ -0,0 +1,22 @@ | |||
/*! | |||
@file AudioUnitSDK/AudioUnitSDK.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_h | |||
#define AudioUnitSDK_h | |||
#include <AudioUnitSDK/AUBase.h> | |||
#include <AudioUnitSDK/AUBuffer.h> | |||
#include <AudioUnitSDK/AUEffectBase.h> | |||
#include <AudioUnitSDK/AUInputElement.h> | |||
#include <AudioUnitSDK/AUMIDIBase.h> | |||
#include <AudioUnitSDK/AUMIDIEffectBase.h> | |||
#include <AudioUnitSDK/AUOutputElement.h> | |||
#include <AudioUnitSDK/AUPlugInDispatch.h> | |||
#include <AudioUnitSDK/AUScopeElement.h> | |||
#include <AudioUnitSDK/AUSilentTimeout.h> | |||
#include <AudioUnitSDK/AUUtility.h> | |||
#include <AudioUnitSDK/ComponentBase.h> | |||
#include <AudioUnitSDK/MusicDeviceBase.h> | |||
#endif /* AudioUnitSDK_h */ |
@@ -0,0 +1,98 @@ | |||
/*! | |||
@file AudioUnitSDK/ComponentBase.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
// self | |||
#include <AudioUnitSDK/AUUtility.h> | |||
#include <AudioUnitSDK/ComponentBase.h> | |||
// std | |||
#include <mutex> | |||
namespace ausdk { | |||
static OSStatus CB_GetComponentDescription( | |||
AudioComponentInstance inInstance, AudioComponentDescription* outDesc); | |||
std::recursive_mutex& ComponentBase::InitializationMutex() | |||
{ | |||
__attribute__((no_destroy)) static std::recursive_mutex global; | |||
return global; | |||
} | |||
ComponentBase::ComponentBase(AudioComponentInstance inInstance) : mComponentInstance(inInstance) | |||
{ | |||
(void)GetComponentDescription(); | |||
} | |||
void ComponentBase::DoPostConstructor() | |||
{ | |||
PostConstructorInternal(); | |||
PostConstructor(); | |||
} | |||
void ComponentBase::DoPreDestructor() | |||
{ | |||
PreDestructor(); | |||
PreDestructorInternal(); | |||
} | |||
OSStatus ComponentBase::AP_Open(void* self, AudioComponentInstance compInstance) | |||
{ | |||
OSStatus result = noErr; | |||
const auto acpi = static_cast<AudioComponentPlugInInstance*>(self); | |||
try { | |||
const std::lock_guard guard{ InitializationMutex() }; | |||
auto* const cb = | |||
static_cast<ComponentBase*>((*acpi->mConstruct)(&acpi->mInstanceStorage, compInstance)); | |||
cb->DoPostConstructor(); // allows base class to do additional initialization | |||
// once the derived class is fully constructed | |||
result = noErr; | |||
} | |||
AUSDK_Catch(result) | |||
if (result != noErr) { | |||
delete acpi; // NOLINT | |||
} | |||
return result; | |||
} | |||
OSStatus ComponentBase::AP_Close(void* self) | |||
{ | |||
OSStatus result = noErr; | |||
try { | |||
const auto acpi = static_cast<AudioComponentPlugInInstance*>(self); | |||
if (const auto acImp = | |||
reinterpret_cast<ComponentBase*>(&acpi->mInstanceStorage)) { // NOLINT | |||
acImp->DoPreDestructor(); | |||
(*acpi->mDestruct)(&acpi->mInstanceStorage); | |||
free(self); // NOLINT manual memory management | |||
} | |||
} | |||
AUSDK_Catch(result) | |||
return result; | |||
} | |||
AudioComponentDescription ComponentBase::GetComponentDescription() const | |||
{ | |||
AudioComponentDescription desc = {}; | |||
if (CB_GetComponentDescription(mComponentInstance, &desc) == noErr) { | |||
return desc; | |||
} | |||
return {}; | |||
} | |||
static OSStatus CB_GetComponentDescription( | |||
AudioComponentInstance inInstance, AudioComponentDescription* outDesc) | |||
{ | |||
const AudioComponent comp = AudioComponentInstanceGetComponent(inInstance); | |||
if (comp != nullptr) { | |||
return AudioComponentGetDescription(comp, outDesc); | |||
} | |||
return kAudio_ParamError; | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,162 @@ | |||
/*! | |||
@file AudioUnitSDK/ComponentBase.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_ComponentBase_h | |||
#define AudioUnitSDK_ComponentBase_h | |||
// module | |||
#include <AudioUnitSDK/AUUtility.h> | |||
// OS | |||
#include <AudioToolbox/AudioUnit.h> | |||
// std | |||
#include <array> | |||
#include <mutex> | |||
#include <new> | |||
namespace ausdk { | |||
/*! | |||
@class ComponentBase | |||
@brief Base class for implementing an `AudioComponentInstance`. | |||
*/ | |||
class ComponentBase { | |||
public: | |||
/// Construct given an AudioComponentInstance, typically from APFactory::Constuct. | |||
explicit ComponentBase(AudioComponentInstance inInstance); | |||
virtual ~ComponentBase() = default; | |||
ComponentBase(const ComponentBase&) = delete; | |||
ComponentBase(ComponentBase&&) = delete; | |||
ComponentBase& operator=(const ComponentBase&) = delete; | |||
ComponentBase& operator=(ComponentBase&&) = delete; | |||
/// Called from dispatchers after constructing an instance. | |||
void DoPostConstructor(); | |||
/// Called from dispatchers before destroying an instance. | |||
void DoPreDestructor(); | |||
/// Obtain the wrapped `AudioComponentInstance` (underlying type of `AudioUnit`, `AudioCodec`, | |||
/// and others). | |||
[[nodiscard]] AudioComponentInstance GetComponentInstance() const noexcept | |||
{ | |||
return mComponentInstance; | |||
} | |||
/// Return the instance's `AudioComponentDescription`. | |||
[[nodiscard]] AudioComponentDescription GetComponentDescription() const; | |||
/// Component dispatch method. | |||
static OSStatus AP_Open(void* self, AudioComponentInstance compInstance); | |||
/// Component dispatch method. | |||
static OSStatus AP_Close(void* self); | |||
/// A mutex which is held during `Open`, since some AU's and the Component Manager itself | |||
/// are not thread-safe against globals. | |||
static std::recursive_mutex& InitializationMutex(); | |||
protected: | |||
// subclasses are free to to override these methods to add functionality | |||
virtual void PostConstructor() {} | |||
virtual void PreDestructor() {} | |||
// these methods, however, are reserved for override only within this SDK | |||
virtual void PostConstructorInternal() {} | |||
virtual void PreDestructorInternal() {} | |||
private: | |||
AudioComponentInstance mComponentInstance; | |||
}; | |||
/*! | |||
@class AudioComponentPlugInInstance | |||
@brief Object which implements an AudioComponentPlugInInterface for the framework, and | |||
which holds the C++ implementation object. | |||
*/ | |||
struct AudioComponentPlugInInstance { | |||
// The AudioComponentPlugInInterface must remain first | |||
AudioComponentPlugInInterface mPlugInInterface; | |||
void* (*mConstruct)(void* memory, AudioComponentInstance ci); | |||
void (*mDestruct)(void* memory); | |||
std::array<void*, 2> mPad; // 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 | |||
@tparam APMethodLookup A class (e.g. AUBaseLookup) which provides a method selector lookup | |||
function. | |||
@tparam Implementor The class which implements the full plug-in (AudioUnit) interface. | |||
@brief Provides an AudioComponentFactoryFunction and a convenience wrapper for | |||
AudioComponentRegister. | |||
*/ | |||
template <class APMethodLookup, class Implementor> | |||
class APFactory { | |||
public: | |||
static void* Construct(void* memory, AudioComponentInstance compInstance) | |||
{ | |||
return new (memory) Implementor(compInstance); // NOLINT manual memory management | |||
} | |||
static void Destruct(void* memory) { static_cast<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 */) | |||
{ | |||
auto* const acpi = // NOLINT owning memory | |||
static_cast<AudioComponentPlugInInstance*>(malloc( // NOLINT manual memory management | |||
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 = nullptr; | |||
acpi->mConstruct = Construct; | |||
acpi->mDestruct = Destruct; | |||
acpi->mPad[0] = nullptr; | |||
acpi->mPad[1] = nullptr; | |||
return &acpi->mPlugInInterface; | |||
} | |||
// 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) | |||
{ | |||
const AudioComponentDescription desc = { type, subtype, manuf, flags, 0 }; | |||
return AudioComponentRegister(&desc, name, vers, Factory); | |||
} | |||
}; | |||
#ifndef AUSDK_EXPORT | |||
#if __GNUC__ | |||
#define AUSDK_EXPORT __attribute__((visibility("default"))) // NOLINT | |||
#else | |||
#warning export? | |||
#endif | |||
#endif | |||
/// Macro to generate the factory function for the specified Audio Component. Factory is an | |||
/// APFactory such as AUBaseFactory. Class is the name of the final ComponentBase class which | |||
/// implements instances of the class. | |||
#define AUSDK_COMPONENT_ENTRY(FactoryType, Class) /* NOLINT macro */ \ | |||
AUSDK_EXPORT \ | |||
extern "C" void* Class##Factory(const AudioComponentDescription* inDesc); \ | |||
extern "C" void* Class##Factory(const AudioComponentDescription* inDesc) \ | |||
{ \ | |||
return FactoryType<Class>::Factory(inDesc); /* NOLINT parens */ \ | |||
} | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_ComponentBase_h |
@@ -0,0 +1,202 @@ | |||
Apache License | |||
Version 2.0, January 2004 | |||
http://www.apache.org/licenses/ | |||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
1. Definitions. | |||
"License" shall mean the terms and conditions for use, reproduction, | |||
and distribution as defined by Sections 1 through 9 of this document. | |||
"Licensor" shall mean the copyright owner or entity authorized by | |||
the copyright owner that is granting the License. | |||
"Legal Entity" shall mean the union of the acting entity and all | |||
other entities that control, are controlled by, or are under common | |||
control with that entity. For the purposes of this definition, | |||
"control" means (i) the power, direct or indirect, to cause the | |||
direction or management of such entity, whether by contract or | |||
otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
outstanding shares, or (iii) beneficial ownership of such entity. | |||
"You" (or "Your") shall mean an individual or Legal Entity | |||
exercising permissions granted by this License. | |||
"Source" form shall mean the preferred form for making modifications, | |||
including but not limited to software source code, documentation | |||
source, and configuration files. | |||
"Object" form shall mean any form resulting from mechanical | |||
transformation or translation of a Source form, including but | |||
not limited to compiled object code, generated documentation, | |||
and conversions to other media types. | |||
"Work" shall mean the work of authorship, whether in Source or | |||
Object form, made available under the License, as indicated by a | |||
copyright notice that is included in or attached to the work | |||
(an example is provided in the Appendix below). | |||
"Derivative Works" shall mean any work, whether in Source or Object | |||
form, that is based on (or derived from) the Work and for which the | |||
editorial revisions, annotations, elaborations, or other modifications | |||
represent, as a whole, an original work of authorship. For the purposes | |||
of this License, Derivative Works shall not include works that remain | |||
separable from, or merely link (or bind by name) to the interfaces of, | |||
the Work and Derivative Works thereof. | |||
"Contribution" shall mean any work of authorship, including | |||
the original version of the Work and any modifications or additions | |||
to that Work or Derivative Works thereof, that is intentionally | |||
submitted to Licensor for inclusion in the Work by the copyright owner | |||
or by an individual or Legal Entity authorized to submit on behalf of | |||
the copyright owner. For the purposes of this definition, "submitted" | |||
means any form of electronic, verbal, or written communication sent | |||
to the Licensor or its representatives, including but not limited to | |||
communication on electronic mailing lists, source code control systems, | |||
and issue tracking systems that are managed by, or on behalf of, the | |||
Licensor for the purpose of discussing and improving the Work, but | |||
excluding communication that is conspicuously marked or otherwise | |||
designated in writing by the copyright owner as "Not a Contribution." | |||
"Contributor" shall mean Licensor and any individual or Legal Entity | |||
on behalf of whom a Contribution has been received by Licensor and | |||
subsequently incorporated within the Work. | |||
2. Grant of Copyright License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
copyright license to reproduce, prepare Derivative Works of, | |||
publicly display, publicly perform, sublicense, and distribute the | |||
Work and such Derivative Works in Source or Object form. | |||
3. Grant of Patent License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
(except as stated in this section) patent license to make, have made, | |||
use, offer to sell, sell, import, and otherwise transfer the Work, | |||
where such license applies only to those patent claims licensable | |||
by such Contributor that are necessarily infringed by their | |||
Contribution(s) alone or by combination of their Contribution(s) | |||
with the Work to which such Contribution(s) was submitted. If You | |||
institute patent litigation against any entity (including a | |||
cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
or a Contribution incorporated within the Work constitutes direct | |||
or contributory patent infringement, then any patent licenses | |||
granted to You under this License for that Work shall terminate | |||
as of the date such litigation is filed. | |||
4. Redistribution. You may reproduce and distribute copies of the | |||
Work or Derivative Works thereof in any medium, with or without | |||
modifications, and in Source or Object form, provided that You | |||
meet the following conditions: | |||
(a) You must give any other recipients of the Work or | |||
Derivative Works a copy of this License; and | |||
(b) You must cause any modified files to carry prominent notices | |||
stating that You changed the files; and | |||
(c) You must retain, in the Source form of any Derivative Works | |||
that You distribute, all copyright, patent, trademark, and | |||
attribution notices from the Source form of the Work, | |||
excluding those notices that do not pertain to any part of | |||
the Derivative Works; and | |||
(d) If the Work includes a "NOTICE" text file as part of its | |||
distribution, then any Derivative Works that You distribute must | |||
include a readable copy of the attribution notices contained | |||
within such NOTICE file, excluding those notices that do not | |||
pertain to any part of the Derivative Works, in at least one | |||
of the following places: within a NOTICE text file distributed | |||
as part of the Derivative Works; within the Source form or | |||
documentation, if provided along with the Derivative Works; or, | |||
within a display generated by the Derivative Works, if and | |||
wherever such third-party notices normally appear. The contents | |||
of the NOTICE file are for informational purposes only and | |||
do not modify the License. You may add Your own attribution | |||
notices within Derivative Works that You distribute, alongside | |||
or as an addendum to the NOTICE text from the Work, provided | |||
that such additional attribution notices cannot be construed | |||
as modifying the License. | |||
You may add Your own copyright statement to Your modifications and | |||
may provide additional or different license terms and conditions | |||
for use, reproduction, or distribution of Your modifications, or | |||
for any such Derivative Works as a whole, provided Your use, | |||
reproduction, and distribution of the Work otherwise complies with | |||
the conditions stated in this License. | |||
5. Submission of Contributions. Unless You explicitly state otherwise, | |||
any Contribution intentionally submitted for inclusion in the Work | |||
by You to the Licensor shall be under the terms and conditions of | |||
this License, without any additional terms or conditions. | |||
Notwithstanding the above, nothing herein shall supersede or modify | |||
the terms of any separate license agreement you may have executed | |||
with Licensor regarding such Contributions. | |||
6. Trademarks. This License does not grant permission to use the trade | |||
names, trademarks, service marks, or product names of the Licensor, | |||
except as required for reasonable and customary use in describing the | |||
origin of the Work and reproducing the content of the NOTICE file. | |||
7. Disclaimer of Warranty. Unless required by applicable law or | |||
agreed to in writing, Licensor provides the Work (and each | |||
Contributor provides its Contributions) on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
implied, including, without limitation, any warranties or conditions | |||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
PARTICULAR PURPOSE. You are solely responsible for determining the | |||
appropriateness of using or redistributing the Work and assume any | |||
risks associated with Your exercise of permissions under this License. | |||
8. Limitation of Liability. In no event and under no legal theory, | |||
whether in tort (including negligence), contract, or otherwise, | |||
unless required by applicable law (such as deliberate and grossly | |||
negligent acts) or agreed to in writing, shall any Contributor be | |||
liable to You for damages, including any direct, indirect, special, | |||
incidental, or consequential damages of any character arising as a | |||
result of this License or out of the use or inability to use the | |||
Work (including but not limited to damages for loss of goodwill, | |||
work stoppage, computer failure or malfunction, or any and all | |||
other commercial damages or losses), even if such Contributor | |||
has been advised of the possibility of such damages. | |||
9. Accepting Warranty or Additional Liability. While redistributing | |||
the Work or Derivative Works thereof, You may choose to offer, | |||
and charge a fee for, acceptance of support, warranty, indemnity, | |||
or other liability obligations and/or rights consistent with this | |||
License. However, in accepting such obligations, You may act only | |||
on Your own behalf and on Your sole responsibility, not on behalf | |||
of any other Contributor, and only if You agree to indemnify, | |||
defend, and hold each Contributor harmless for any liability | |||
incurred by, or claims asserted against, such Contributor by reason | |||
of your accepting any such warranty or additional liability. | |||
END OF TERMS AND CONDITIONS | |||
APPENDIX: How to apply the Apache License to your work. | |||
To apply the Apache License to your work, attach the following | |||
boilerplate notice, with the fields enclosed by brackets "[]" | |||
replaced with your own identifying information. (Don't include | |||
the brackets!) The text should be enclosed in the appropriate | |||
comment syntax for the file format. We also recommend that a | |||
file or class name and description of purpose be included on the | |||
same "printed page" as the copyright notice for easier | |||
identification within third-party archives. | |||
Copyright [yyyy] [name of copyright owner] | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. |
@@ -0,0 +1,117 @@ | |||
/*! | |||
@file AudioUnitSDK/MusicDeviceBase.cpp | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#include <AudioUnitSDK/MusicDeviceBase.h> | |||
namespace ausdk { | |||
MusicDeviceBase::MusicDeviceBase( | |||
AudioComponentInstance inInstance, UInt32 numInputs, UInt32 numOutputs, UInt32 numGroups) | |||
: AUBase(inInstance, numInputs, numOutputs, numGroups), AUMIDIBase(*static_cast<AUBase*>(this)) | |||
{ | |||
} | |||
OSStatus MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) | |||
{ | |||
OSStatus result = noErr; | |||
switch (inID) { // NOLINT if/else | |||
case kMusicDeviceProperty_InstrumentCount: | |||
if (inScope != kAudioUnitScope_Global) { | |||
return kAudioUnitErr_InvalidScope; | |||
} | |||
outDataSize = sizeof(UInt32); | |||
outWritable = false; | |||
result = noErr; | |||
break; | |||
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 = noErr; | |||
switch (inID) { // NOLINT if/else | |||
case kMusicDeviceProperty_InstrumentCount: | |||
if (inScope != kAudioUnitScope_Global) { | |||
return kAudioUnitErr_InvalidScope; | |||
} | |||
return GetInstrumentCount(*static_cast<UInt32*>(outData)); | |||
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) | |||
{ | |||
const MusicDeviceNoteParams params{ .argCount = 2, | |||
.mPitch = static_cast<Float32>(inNoteNumber), | |||
.mVelocity = static_cast<Float32>(inVelocity) }; | |||
return StartNote(kMusicNoteEvent_UseGroupInstrument, inChannel, nullptr, 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 == nullptr || outNoteInstanceID == nullptr) { | |||
return kAudio_ParamError; | |||
} | |||
if (!IsInitialized()) { | |||
return kAudioUnitErr_Uninitialized; | |||
} | |||
return StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams); | |||
} | |||
} // namespace ausdk |
@@ -0,0 +1,64 @@ | |||
/*! | |||
@file AudioUnitSDK/MusicDeviceBase.h | |||
@copyright © 2000-2021 Apple Inc. All rights reserved. | |||
*/ | |||
#ifndef AudioUnitSDK_MusicDeviceBase_h | |||
#define AudioUnitSDK_MusicDeviceBase_h | |||
#include <AudioUnitSDK/AUMIDIBase.h> | |||
namespace ausdk { | |||
// ________________________________________________________________________ | |||
// MusicDeviceBase | |||
// | |||
/*! | |||
@class MusicDeviceBase | |||
@brief Deriving from AUBase and AUMIDIBase, an abstract base class for Music Device | |||
subclasses. | |||
*/ | |||
class MusicDeviceBase : public AUBase, public AUMIDIBase { | |||
public: | |||
MusicDeviceBase(AudioComponentInstance inInstance, UInt32 numInputs, UInt32 numOutputs, | |||
UInt32 numGroups = 0); | |||
OSStatus MIDIEvent( | |||
UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame) override | |||
{ | |||
return AUMIDIBase::MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); | |||
} | |||
OSStatus SysEx(const UInt8* inData, UInt32 inLength) override | |||
{ | |||
return AUMIDIBase::SysEx(inData, inLength); | |||
} | |||
#if AUSDK_MIDI2_AVAILABLE | |||
OSStatus MIDIEventList( | |||
UInt32 inOffsetSampleFrame, const struct MIDIEventList* eventList) override | |||
{ | |||
return AUMIDIBase::MIDIEventList(inOffsetSampleFrame, eventList); | |||
} | |||
#endif | |||
OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, UInt32& outDataSize, bool& outWritable) override; | |||
OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, void* outData) override; | |||
OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, | |||
AudioUnitElement inElement, const void* inData, UInt32 inDataSize) override; | |||
OSStatus HandleNoteOn( | |||
UInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) override; | |||
OSStatus HandleNoteOff( | |||
UInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) override; | |||
virtual OSStatus GetInstrumentCount(UInt32& outInstCount) const; | |||
private: | |||
OSStatus HandleStartNoteMessage(MusicDeviceInstrumentID inInstrument, | |||
MusicDeviceGroupID inGroupID, NoteInstanceID* outNoteInstanceID, UInt32 inOffsetSampleFrame, | |||
const MusicDeviceNoteParams* inParams); | |||
}; | |||
} // namespace ausdk | |||
#endif // AudioUnitSDK_MusicDeviceBase_h |
@@ -1,75 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,219 +0,0 @@ | |||
/* | |||
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 |
@@ -1,267 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,438 +0,0 @@ | |||
/* | |||
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; | |||
} |
@@ -1,82 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,151 +0,0 @@ | |||
/* | |||
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); | |||
} |
@@ -1,119 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,155 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,495 +0,0 @@ | |||
/* | |||
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" | |||
//temporary 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 |
@@ -1,213 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,76 +0,0 @@ | |||
/* | |||
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 |
@@ -1,82 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,63 +0,0 @@ | |||
/* | |||
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; | |||
} |
@@ -1,66 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,668 +0,0 @@ | |||
/* | |||
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 |
@@ -1,144 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,566 +0,0 @@ | |||
/* | |||
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; | |||
} |
@@ -1,553 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,93 +0,0 @@ | |||
/* | |||
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 |
@@ -1,163 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,88 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,401 +0,0 @@ | |||
/* | |||
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 |
@@ -1,191 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,305 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,239 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,153 +0,0 @@ | |||
/* | |||
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]); | |||
} | |||
} | |||
} |
@@ -1,199 +0,0 @@ | |||
/* | |||
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 |
@@ -1,508 +0,0 @@ | |||
/* | |||
File: CAAutoDisposer.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(__CAPtr_h__) | |||
#define __CAPtr_h__ | |||
#include <stdlib.h> // for malloc | |||
#include <new> // for bad_alloc | |||
#include <string.h> // for memset | |||
inline void* CA_malloc(size_t size) | |||
{ | |||
void* p = malloc(size); | |||
if (!p && size) throw std::bad_alloc(); | |||
return p; | |||
} | |||
inline void* CA_realloc(void* old, size_t size) | |||
{ | |||
#if TARGET_OS_WIN32 | |||
void* p = realloc(old, size); | |||
#else | |||
void* p = reallocf(old, size); // reallocf ensures the old pointer is freed if memory is full (p is NULL). | |||
#endif | |||
if (!p && size) throw std::bad_alloc(); | |||
return p; | |||
} | |||
#ifndef UINTPTR_MAX | |||
#if __LP64__ | |||
#define UINTPTR_MAX 18446744073709551615ULL | |||
#else | |||
#define UINTPTR_MAX 4294967295U | |||
#endif | |||
#endif | |||
inline void* CA_calloc(size_t n, size_t size) | |||
{ | |||
// ensure that multiplication will not overflow | |||
if (n && UINTPTR_MAX / n < size) throw std::bad_alloc(); | |||
size_t nsize = n*size; | |||
void* p = malloc(nsize); | |||
if (!p && nsize) throw std::bad_alloc(); | |||
memset(p, 0, nsize); | |||
return p; | |||
} | |||
// helper class for automatic conversions | |||
template <typename T> | |||
struct CAPtrRef | |||
{ | |||
T* ptr_; | |||
explicit CAPtrRef(T* ptr) : ptr_(ptr) {} | |||
}; | |||
template <typename T> | |||
class CAAutoFree | |||
{ | |||
private: | |||
T* ptr_; | |||
public: | |||
CAAutoFree() : ptr_(0) {} | |||
explicit CAAutoFree(T* ptr) : ptr_(ptr) {} | |||
template<typename U> | |||
CAAutoFree(CAAutoFree<U>& that) : ptr_(that.release()) {} // take ownership | |||
// C++ std says: a template constructor is never a copy constructor | |||
CAAutoFree(CAAutoFree<T>& that) : ptr_(that.release()) {} // take ownership | |||
CAAutoFree(size_t n, bool clear = false) | |||
// this becomes an ambiguous call if n == 0 | |||
: ptr_(0) | |||
{ | |||
size_t maxItems = ~size_t(0) / sizeof(T); | |||
if (n > maxItems) | |||
throw std::bad_alloc(); | |||
ptr_ = static_cast<T*>(clear ? CA_calloc(n, sizeof(T)) : CA_malloc(n * sizeof(T))); | |||
} | |||
~CAAutoFree() { free(); } | |||
void alloc(size_t numItems, bool clear = false) | |||
{ | |||
size_t maxItems = ~size_t(0) / sizeof(T); | |||
if (numItems > maxItems) throw std::bad_alloc(); | |||
free(); | |||
ptr_ = static_cast<T*>(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T))); | |||
} | |||
void allocBytes(size_t numBytes, bool clear = false) | |||
{ | |||
free(); | |||
ptr_ = static_cast<T*>(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes)); | |||
} | |||
void reallocBytes(size_t numBytes) | |||
{ | |||
ptr_ = static_cast<T*>(CA_realloc(ptr_, numBytes)); | |||
} | |||
void reallocItems(size_t numItems) | |||
{ | |||
size_t maxItems = ~size_t(0) / sizeof(T); | |||
if (numItems > maxItems) throw std::bad_alloc(); | |||
ptr_ = static_cast<T*>(CA_realloc(ptr_, numItems * sizeof(T))); | |||
} | |||
template <typename U> | |||
CAAutoFree& operator=(CAAutoFree<U>& that) | |||
{ | |||
set(that.release()); // take ownership | |||
return *this; | |||
} | |||
CAAutoFree& operator=(CAAutoFree& that) | |||
{ | |||
set(that.release()); // take ownership | |||
return *this; | |||
} | |||
CAAutoFree& operator=(T* ptr) | |||
{ | |||
set(ptr); | |||
return *this; | |||
} | |||
template <typename U> | |||
CAAutoFree& operator=(U* ptr) | |||
{ | |||
set(ptr); | |||
return *this; | |||
} | |||
T& operator*() const { return *ptr_; } | |||
T* operator->() const { return ptr_; } | |||
T* operator()() const { return ptr_; } | |||
T* get() const { return ptr_; } | |||
operator T*() const { return ptr_; } | |||
bool operator==(CAAutoFree const& that) const { return ptr_ == that.ptr_; } | |||
bool operator!=(CAAutoFree const& that) const { return ptr_ != that.ptr_; } | |||
bool operator==(T* ptr) const { return ptr_ == ptr; } | |||
bool operator!=(T* ptr) const { return ptr_ != ptr; } | |||
T* release() | |||
{ | |||
// release ownership | |||
T* result = ptr_; | |||
ptr_ = 0; | |||
return result; | |||
} | |||
void set(T* ptr) | |||
{ | |||
if (ptr != ptr_) | |||
{ | |||
::free(ptr_); | |||
ptr_ = ptr; | |||
} | |||
} | |||
void free() | |||
{ | |||
set(0); | |||
} | |||
// automatic conversions to allow assignment from results of functions. | |||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book. | |||
CAAutoFree(CAPtrRef<T> ref) : ptr_(ref.ptr_) { } | |||
CAAutoFree& operator=(CAPtrRef<T> ref) | |||
{ | |||
set(ref.ptr_); | |||
return *this; | |||
} | |||
template<typename U> | |||
operator CAPtrRef<U>() | |||
{ return CAPtrRef<U>(release()); } | |||
template<typename U> | |||
operator CAAutoFree<U>() | |||
{ return CAAutoFree<U>(release()); } | |||
}; | |||
template <typename T> | |||
class CAAutoDelete | |||
{ | |||
private: | |||
T* ptr_; | |||
public: | |||
CAAutoDelete() : ptr_(0) {} | |||
explicit CAAutoDelete(T* ptr) : ptr_(ptr) {} | |||
template<typename U> | |||
CAAutoDelete(CAAutoDelete<U>& that) : ptr_(that.release()) {} // take ownership | |||
// C++ std says: a template constructor is never a copy constructor | |||
CAAutoDelete(CAAutoDelete<T>& that) : ptr_(that.release()) {} // take ownership | |||
~CAAutoDelete() { free(); } | |||
template <typename U> | |||
CAAutoDelete& operator=(CAAutoDelete<U>& that) | |||
{ | |||
set(that.release()); // take ownership | |||
return *this; | |||
} | |||
CAAutoDelete& operator=(CAAutoDelete& that) | |||
{ | |||
set(that.release()); // take ownership | |||
return *this; | |||
} | |||
CAAutoDelete& operator=(T* ptr) | |||
{ | |||
set(ptr); | |||
return *this; | |||
} | |||
template <typename U> | |||
CAAutoDelete& operator=(U* ptr) | |||
{ | |||
set(ptr); | |||
return *this; | |||
} | |||
T& operator*() const { return *ptr_; } | |||
T* operator->() const { return ptr_; } | |||
T* operator()() const { return ptr_; } | |||
T* get() const { return ptr_; } | |||
operator T*() const { return ptr_; } | |||
bool operator==(CAAutoDelete const& that) const { return ptr_ == that.ptr_; } | |||
bool operator!=(CAAutoDelete const& that) const { return ptr_ != that.ptr_; } | |||
bool operator==(T* ptr) const { return ptr_ == ptr; } | |||
bool operator!=(T* ptr) const { return ptr_ != ptr; } | |||
T* release() | |||
{ | |||
// release ownership | |||
T* result = ptr_; | |||
ptr_ = 0; | |||
return result; | |||
} | |||
void set(T* ptr) | |||
{ | |||
if (ptr != ptr_) | |||
{ | |||
delete ptr_; | |||
ptr_ = ptr; | |||
} | |||
} | |||
void free() | |||
{ | |||
set(0); | |||
} | |||
// automatic conversions to allow assignment from results of functions. | |||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book. | |||
CAAutoDelete(CAPtrRef<T> ref) : ptr_(ref.ptr_) { } | |||
CAAutoDelete& operator=(CAPtrRef<T> ref) | |||
{ | |||
set(ref.ptr_); | |||
return *this; | |||
} | |||
template<typename U> | |||
operator CAPtrRef<U>() | |||
{ return CAPtrRef<U>(release()); } | |||
template<typename U> | |||
operator CAAutoFree<U>() | |||
{ return CAAutoFree<U>(release()); } | |||
}; | |||
template <typename T> | |||
class CAAutoArrayDelete | |||
{ | |||
private: | |||
T* ptr_; | |||
public: | |||
CAAutoArrayDelete() : ptr_(0) {} | |||
explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {} | |||
template<typename U> | |||
CAAutoArrayDelete(CAAutoArrayDelete<U>& that) : ptr_(that.release()) {} // take ownership | |||
// C++ std says: a template constructor is never a copy constructor | |||
CAAutoArrayDelete(CAAutoArrayDelete<T>& that) : ptr_(that.release()) {} // take ownership | |||
// this becomes an ambiguous call if n == 0 | |||
CAAutoArrayDelete(size_t n) : ptr_(new T[n]) {} | |||
~CAAutoArrayDelete() { free(); } | |||
void alloc(size_t numItems) | |||
{ | |||
free(); | |||
ptr_ = new T [numItems]; | |||
} | |||
template <typename U> | |||
CAAutoArrayDelete& operator=(CAAutoArrayDelete<U>& that) | |||
{ | |||
set(that.release()); // take ownership | |||
return *this; | |||
} | |||
CAAutoArrayDelete& operator=(CAAutoArrayDelete& that) | |||
{ | |||
set(that.release()); // take ownership | |||
return *this; | |||
} | |||
CAAutoArrayDelete& operator=(T* ptr) | |||
{ | |||
set(ptr); | |||
return *this; | |||
} | |||
template <typename U> | |||
CAAutoArrayDelete& operator=(U* ptr) | |||
{ | |||
set(ptr); | |||
return *this; | |||
} | |||
T& operator*() const { return *ptr_; } | |||
T* operator->() const { return ptr_; } | |||
T* operator()() const { return ptr_; } | |||
T* get() const { return ptr_; } | |||
operator T*() const { return ptr_; } | |||
bool operator==(CAAutoArrayDelete const& that) const { return ptr_ == that.ptr_; } | |||
bool operator!=(CAAutoArrayDelete const& that) const { return ptr_ != that.ptr_; } | |||
bool operator==(T* ptr) const { return ptr_ == ptr; } | |||
bool operator!=(T* ptr) const { return ptr_ != ptr; } | |||
T* release() | |||
{ | |||
// release ownership | |||
T* result = ptr_; | |||
ptr_ = 0; | |||
return result; | |||
} | |||
void set(T* ptr) | |||
{ | |||
if (ptr != ptr_) | |||
{ | |||
delete [] ptr_; | |||
ptr_ = ptr; | |||
} | |||
} | |||
void free() | |||
{ | |||
set(0); | |||
} | |||
// automatic conversions to allow assignment from results of functions. | |||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book. | |||
CAAutoArrayDelete(CAPtrRef<T> ref) : ptr_(ref.ptr_) { } | |||
CAAutoArrayDelete& operator=(CAPtrRef<T> ref) | |||
{ | |||
set(ref.ptr_); | |||
return *this; | |||
} | |||
template<typename U> | |||
operator CAPtrRef<U>() | |||
{ return CAPtrRef<U>(release()); } | |||
template<typename U> | |||
operator CAAutoArrayDelete<U>() | |||
{ return CAAutoFree<U>(release()); } | |||
}; | |||
// convenience function | |||
template <typename T> | |||
void free(CAAutoFree<T>& p) | |||
{ | |||
p.free(); | |||
} | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#if 0 | |||
// example program showing ownership transfer | |||
CAAutoFree<char> source() | |||
{ | |||
// source allocates and returns ownership to the caller. | |||
const char* str = "this is a test"; | |||
size_t size = strlen(str) + 1; | |||
CAAutoFree<char> captr(size, false); | |||
strlcpy(captr(), str, size); | |||
printf("source %08X %08X '%s'\n", &captr, captr(), captr()); | |||
return captr; | |||
} | |||
void user(CAAutoFree<char> const& captr) | |||
{ | |||
// passed by const reference. user can access the pointer but does not take ownership. | |||
printf("user: %08X %08X '%s'\n", &captr, captr(), captr()); | |||
} | |||
void sink(CAAutoFree<char> captr) | |||
{ | |||
// passed by value. sink takes ownership and frees the pointer on return. | |||
printf("sink: %08X %08X '%s'\n", &captr, captr(), captr()); | |||
} | |||
int main (int argc, char * const argv[]) | |||
{ | |||
CAAutoFree<char> captr(source()); | |||
printf("main captr A %08X %08X\n", &captr, captr()); | |||
user(captr); | |||
sink(captr); | |||
printf("main captr B %08X %08X\n", &captr, captr()); | |||
return 0; | |||
} | |||
#endif | |||
#endif |
@@ -1,583 +0,0 @@ | |||
/* | |||
File: CADebugMacros.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(__CADebugMacros_h__) | |||
#define __CADebugMacros_h__ | |||
#pragma clang diagnostic ignored "-Wdeprecated-declarations" | |||
//============================================================================= | |||
// Includes | |||
//============================================================================= | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#else | |||
#include "CoreAudioTypes.h" | |||
#endif | |||
//============================================================================= | |||
// CADebugMacros | |||
//============================================================================= | |||
//#define CoreAudio_StopOnFailure 1 | |||
//#define CoreAudio_TimeStampMessages 1 | |||
//#define CoreAudio_ThreadStampMessages 1 | |||
//#define CoreAudio_FlushDebugMessages 1 | |||
#if TARGET_RT_BIG_ENDIAN | |||
#define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } | |||
#define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[0]; theCString[1] = ((char*)&the4CC)[1]; theCString[2] = ((char*)&the4CC)[2]; theCString[3] = ((char*)&the4CC)[3]; theCString[4] = 0; } | |||
#else | |||
#define CA4CCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 } | |||
#define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[3]; theCString[1] = ((char*)&the4CC)[2]; theCString[2] = ((char*)&the4CC)[1]; theCString[3] = ((char*)&the4CC)[0]; theCString[4] = 0; } | |||
#endif | |||
// This is a macro that does a sizeof and casts the result to a UInt32. This is useful for all the | |||
// places where -wshorten64-32 catches assigning a sizeof expression to a UInt32. | |||
// For want of a better place to park this, we'll park it here. | |||
#define SizeOf32(X) ((UInt32)sizeof(X)) | |||
// This is a macro that does a offsetof and casts the result to a UInt32. This is useful for all the | |||
// places where -wshorten64-32 catches assigning an offsetof expression to a UInt32. | |||
// For want of a better place to park this, we'll park it here. | |||
#define OffsetOf32(X, Y) ((UInt32)offsetof(X, Y)) | |||
// This macro casts the expression to a UInt32. It is called out specially to allow us to track casts | |||
// that have been added purely to avert -wshorten64-32 warnings on 64 bit platforms. | |||
// For want of a better place to park this, we'll park it here. | |||
#define ToUInt32(X) ((UInt32)(X)) | |||
#define ToSInt32(X) ((SInt32)(X)) | |||
#pragma mark Basic Definitions | |||
#if DEBUG || CoreAudio_Debug | |||
// can be used to break into debugger immediately, also see CADebugger | |||
#define BusError() { long* p=NULL; *p=0; } | |||
// basic debugging print routines | |||
#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON | |||
extern void DebugStr(const unsigned char* debuggerMsg); | |||
#define DebugMessage(msg) DebugStr("\p"msg) | |||
#define DebugMessageN1(msg, N1) | |||
#define DebugMessageN2(msg, N1, N2) | |||
#define DebugMessageN3(msg, N1, N2, N3) | |||
#else | |||
#include "CADebugPrintf.h" | |||
#if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile) | |||
#define FlushRtn ,fflush(DebugPrintfFile) | |||
#else | |||
#define FlushRtn | |||
#endif | |||
#if CoreAudio_ThreadStampMessages | |||
#include <pthread.h> | |||
#include "CAHostTimeBase.h" | |||
#if TARGET_RT_64_BIT | |||
#define DebugPrintfThreadIDFormat "%16p" | |||
#else | |||
#define DebugPrintfThreadIDFormat "%8p" | |||
#endif | |||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn | |||
#elif CoreAudio_TimeStampMessages | |||
#include "CAHostTimeBase.h" | |||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn | |||
#else | |||
#define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn | |||
#endif | |||
#endif | |||
void DebugPrint(const char *fmt, ...); // can be used like printf | |||
#ifndef DEBUGPRINT | |||
#define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h) | |||
#endif | |||
#if VERBOSE | |||
#define vprint(msg) DEBUGPRINT(msg) | |||
#else | |||
#define vprint(msg) | |||
#endif | |||
// Original macro keeps its function of turning on and off use of CADebuggerStop() for both asserts and throws. | |||
// For backwards compat, it overrides any setting of the two sub-macros. | |||
#if CoreAudio_StopOnFailure | |||
#include "CADebugger.h" | |||
#undef CoreAudio_StopOnAssert | |||
#define CoreAudio_StopOnAssert 1 | |||
#undef CoreAudio_StopOnThrow | |||
#define CoreAudio_StopOnThrow 1 | |||
#define STOP CADebuggerStop() | |||
#else | |||
#define STOP | |||
#endif | |||
#if CoreAudio_StopOnAssert | |||
#if !CoreAudio_StopOnFailure | |||
#include "CADebugger.h" | |||
#define STOP | |||
#endif | |||
#define __ASSERT_STOP CADebuggerStop() | |||
#else | |||
#define __ASSERT_STOP | |||
#endif | |||
#if CoreAudio_StopOnThrow | |||
#if !CoreAudio_StopOnFailure | |||
#include "CADebugger.h" | |||
#define STOP | |||
#endif | |||
#define __THROW_STOP CADebuggerStop() | |||
#else | |||
#define __THROW_STOP | |||
#endif | |||
#else | |||
#define DebugMsg(inFormat, ...) | |||
#ifndef DEBUGPRINT | |||
#define DEBUGPRINT(msg) | |||
#endif | |||
#define vprint(msg) | |||
#define STOP | |||
#define __ASSERT_STOP | |||
#define __THROW_STOP | |||
#endif | |||
// Old-style numbered DebugMessage calls are implemented in terms of DebugMsg() now | |||
#define DebugMessage(msg) DebugMsg(msg) | |||
#define DebugMessageN1(msg, N1) DebugMsg(msg, N1) | |||
#define DebugMessageN2(msg, N1, N2) DebugMsg(msg, N1, N2) | |||
#define DebugMessageN3(msg, N1, N2, N3) DebugMsg(msg, N1, N2, N3) | |||
#define DebugMessageN4(msg, N1, N2, N3, N4) DebugMsg(msg, N1, N2, N3, N4) | |||
#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugMsg(msg, N1, N2, N3, N4, N5) | |||
#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugMsg(msg, N1, N2, N3, N4, N5, N6) | |||
#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7) | |||
#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8) | |||
#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) | |||
void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging) | |||
void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging) | |||
#define NO_ACTION (void)0 | |||
#if DEBUG || CoreAudio_Debug | |||
#pragma mark Debug Macros | |||
#define Assert(inCondition, inMessage) \ | |||
if(!(inCondition)) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
__ASSERT_STOP; \ | |||
} | |||
#define AssertFileLine(inCondition, inMessage) \ | |||
if(!(inCondition)) \ | |||
{ \ | |||
DebugMessageN3("%s, line %d: %s", __FILE__, __LINE__, inMessage); \ | |||
__ASSERT_STOP; \ | |||
} | |||
#define AssertNoError(inError, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
char __4CC[5] = CA4CCToCString(__Err); \ | |||
DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} | |||
#define AssertNoKernelError(inError, inMessage) \ | |||
{ \ | |||
unsigned int __Err = (unsigned int)(inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} | |||
#define AssertNotNULL(inPtr, inMessage) \ | |||
{ \ | |||
if((inPtr) == NULL) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} | |||
#define FailIf(inCondition, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
STOP; \ | |||
goto inHandler; \ | |||
} | |||
#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ | |||
if((inPointer) == NULL) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ | |||
{ \ | |||
unsigned int __Err = (inKernelError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} \ | |||
} | |||
#define FailIfError(inError, inAction, inHandler, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
char __4CC[5] = CA4CCToCString(__Err); \ | |||
DebugMessageN2(inMessage ", Error: %ld (%s)", (long int)__Err, __4CC); \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} \ | |||
} | |||
#define FailIfNoMessage(inCondition, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
STOP; \ | |||
goto inHandler; \ | |||
} | |||
#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ | |||
if((inPointer) == NULL) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ | |||
{ \ | |||
unsigned int __Err = (inKernelError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} \ | |||
} | |||
#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} \ | |||
} | |||
#if defined(__cplusplus) | |||
#define Throw(inException) __THROW_STOP; throw (inException) | |||
#define ThrowIf(inCondition, inException, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
Throw(inException); \ | |||
} | |||
#define ThrowIfNULL(inPointer, inException, inMessage) \ | |||
if((inPointer) == NULL) \ | |||
{ \ | |||
DebugMessage(inMessage); \ | |||
Throw(inException); \ | |||
} | |||
#define ThrowIfKernelError(inKernelError, inException, inMessage) \ | |||
{ \ | |||
int __Err = (inKernelError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ | |||
Throw(inException); \ | |||
} \ | |||
} | |||
#define ThrowIfError(inError, inException, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
char __4CC[5] = CA4CCToCString(__Err); \ | |||
DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ | |||
Throw(inException); \ | |||
} \ | |||
} | |||
#if TARGET_OS_WIN32 | |||
#define ThrowIfWinError(inError, inException, inMessage) \ | |||
{ \ | |||
HRESULT __Err = (inError); \ | |||
if(FAILED(__Err)) \ | |||
{ \ | |||
DebugMessageN2(inMessage ", Code: %d, Facility: 0x%X", HRESULT_CODE(__Err), HRESULT_FACILITY(__Err)); \ | |||
Throw(inException); \ | |||
} \ | |||
} | |||
#endif | |||
#define SubclassResponsibility(inMethodName, inException) \ | |||
{ \ | |||
DebugMessage(inMethodName": Subclasses must implement this method"); \ | |||
Throw(inException); \ | |||
} | |||
#endif // defined(__cplusplus) | |||
#else | |||
#pragma mark Release Macros | |||
#define Assert(inCondition, inMessage) \ | |||
if(!(inCondition)) \ | |||
{ \ | |||
__ASSERT_STOP; \ | |||
} | |||
#define AssertFileLine(inCondition, inMessage) Assert(inCondition, inMessage) | |||
#define AssertNoError(inError, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} | |||
#define AssertNoKernelError(inError, inMessage) \ | |||
{ \ | |||
unsigned int __Err = (unsigned int)(inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} | |||
#define AssertNotNULL(inPtr, inMessage) \ | |||
{ \ | |||
if((inPtr) == NULL) \ | |||
{ \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} | |||
#define FailIf(inCondition, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
STOP; \ | |||
goto inHandler; \ | |||
} | |||
#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ | |||
if((inPointer) == NULL) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ | |||
if((inKernelError) != 0) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfError(inError, inAction, inHandler, inMessage) \ | |||
if((inError) != 0) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfNoMessage(inCondition, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
STOP; \ | |||
goto inHandler; \ | |||
} | |||
#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ | |||
if((inPointer) == NULL) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} | |||
#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ | |||
{ \ | |||
unsigned int __Err = (inKernelError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} \ | |||
} | |||
#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
STOP; \ | |||
{ inAction; } \ | |||
goto inHandler; \ | |||
} \ | |||
} | |||
#if defined(__cplusplus) | |||
#define Throw(inException) __THROW_STOP; throw (inException) | |||
#define ThrowIf(inCondition, inException, inMessage) \ | |||
if(inCondition) \ | |||
{ \ | |||
Throw(inException); \ | |||
} | |||
#define ThrowIfNULL(inPointer, inException, inMessage) \ | |||
if((inPointer) == NULL) \ | |||
{ \ | |||
Throw(inException); \ | |||
} | |||
#define ThrowIfKernelError(inKernelError, inException, inMessage) \ | |||
{ \ | |||
int __Err = (inKernelError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
Throw(inException); \ | |||
} \ | |||
} | |||
#define ThrowIfError(inError, inException, inMessage) \ | |||
{ \ | |||
SInt32 __Err = (inError); \ | |||
if(__Err != 0) \ | |||
{ \ | |||
Throw(inException); \ | |||
} \ | |||
} | |||
#if TARGET_OS_WIN32 | |||
#define ThrowIfWinError(inError, inException, inMessage) \ | |||
{ \ | |||
HRESULT __Err = (inError); \ | |||
if(FAILED(__Err)) \ | |||
{ \ | |||
Throw(inException); \ | |||
} \ | |||
} | |||
#endif | |||
#define SubclassResponsibility(inMethodName, inException) \ | |||
{ \ | |||
Throw(inException); \ | |||
} | |||
#endif // defined(__cplusplus) | |||
#endif // DEBUG || CoreAudio_Debug | |||
#endif |
@@ -1,115 +0,0 @@ | |||
/* | |||
File: CADebugPrintf.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(__CADebugPrintf_h__) | |||
#define __CADebugPrintf_h__ | |||
//============================================================================= | |||
// Includes | |||
//============================================================================= | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#else | |||
#include "CoreAudioTypes.h" | |||
#endif | |||
//============================================================================= | |||
// Macros to redirect debugging output to various logging services | |||
//============================================================================= | |||
//#define CoreAudio_UseSysLog 1 | |||
//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt" | |||
#if DEBUG || CoreAudio_Debug | |||
#if TARGET_OS_WIN32 | |||
#if defined(__cplusplus) | |||
extern "C" | |||
#endif | |||
extern int CAWin32DebugPrintf(char* inFormat, ...); | |||
#define DebugPrintfRtn CAWin32DebugPrintf | |||
#define DebugPrintfFile | |||
#define DebugPrintfLineEnding "\n" | |||
#define DebugPrintfFileComma | |||
#else | |||
#if CoreAudio_UseSysLog | |||
#include <sys/syslog.h> | |||
#define DebugPrintfRtn syslog | |||
#define DebugPrintfFile LOG_NOTICE | |||
#define DebugPrintfLineEnding "" | |||
#define DebugPrintfFileComma DebugPrintfFile, | |||
#elif defined(CoreAudio_UseSideFile) | |||
#include <stdio.h> | |||
#if defined(__cplusplus) | |||
extern "C" | |||
#endif | |||
void OpenDebugPrintfSideFile(); | |||
extern FILE* sDebugPrintfSideFile; | |||
#define DebugPrintfRtn fprintf | |||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr) | |||
#define DebugPrintfLineEnding "\n" | |||
#define DebugPrintfFileComma DebugPrintfFile, | |||
#else | |||
#include <stdio.h> | |||
#define DebugPrintfRtn fprintf | |||
#define DebugPrintfFile stderr | |||
#define DebugPrintfLineEnding "\n" | |||
#define DebugPrintfFileComma DebugPrintfFile, | |||
#endif | |||
#endif | |||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__) | |||
#else | |||
#define DebugPrintfRtn | |||
#define DebugPrintfFile | |||
#define DebugPrintfLineEnding | |||
#define DebugPrintfFileComma | |||
#define DebugPrintf(inFormat, ...) | |||
#endif | |||
#endif |
@@ -1,83 +0,0 @@ | |||
/* | |||
File: CAException.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(__CAException_h__) | |||
#define __CAException_h__ | |||
//============================================================================= | |||
// Includes | |||
//============================================================================= | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#else | |||
#include "CoreAudioTypes.h" | |||
#endif | |||
//============================================================================= | |||
// CAException | |||
//============================================================================= | |||
class CAException | |||
{ | |||
public: | |||
CAException(OSStatus inError) : mError(inError) {} | |||
CAException(const CAException& inException) : mError(inException.mError) {} | |||
CAException& operator=(const CAException& inException) { mError = inException.mError; return *this; } | |||
~CAException() {} | |||
OSStatus GetError() const { return mError; } | |||
protected: | |||
OSStatus mError; | |||
}; | |||
#define CATry try{ | |||
#define CACatch } catch(...) {} | |||
#define CASwallowException(inExpression) try { inExpression; } catch(...) {} | |||
#endif |
@@ -1,234 +0,0 @@ | |||
/* | |||
File: CAHostTimeBase.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(__CAHostTimeBase_h__) | |||
#define __CAHostTimeBase_h__ | |||
//============================================================================= | |||
// Includes | |||
//============================================================================= | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#else | |||
#include <CoreAudioTypes.h> | |||
#endif | |||
#if TARGET_OS_MAC | |||
#include <mach/mach_time.h> | |||
#include <pthread.h> | |||
#elif TARGET_OS_WIN32 | |||
#include <windows.h> | |||
#include "WinPThreadDefs.h" | |||
#else | |||
#error Unsupported operating system | |||
#endif | |||
#include "CADebugPrintf.h" | |||
//============================================================================= | |||
// CAHostTimeBase | |||
// | |||
// This class provides platform independent access to the host's time base. | |||
//============================================================================= | |||
#if CoreAudio_Debug | |||
// #define Log_Host_Time_Base_Parameters 1 | |||
// #define Track_Host_TimeBase 1 | |||
#endif | |||
class CAHostTimeBase | |||
{ | |||
public: | |||
static UInt64 ConvertToNanos(UInt64 inHostTime); | |||
static UInt64 ConvertFromNanos(UInt64 inNanos); | |||
static UInt64 GetTheCurrentTime(); | |||
#if TARGET_OS_MAC | |||
static UInt64 GetCurrentTime() { return GetTheCurrentTime(); } | |||
#endif | |||
static UInt64 GetCurrentTimeInNanos(); | |||
static Float64 GetFrequency() { pthread_once(&sIsInited, Initialize); return sFrequency; } | |||
static Float64 GetInverseFrequency() { pthread_once(&sIsInited, Initialize); return sInverseFrequency; } | |||
static UInt32 GetMinimumDelta() { pthread_once(&sIsInited, Initialize); return sMinDelta; } | |||
static UInt64 AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); | |||
static SInt64 HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); | |||
static UInt64 MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator); | |||
private: | |||
static void Initialize(); | |||
static pthread_once_t sIsInited; | |||
static Float64 sFrequency; | |||
static Float64 sInverseFrequency; | |||
static UInt32 sMinDelta; | |||
static UInt32 sToNanosNumerator; | |||
static UInt32 sToNanosDenominator; | |||
#if Track_Host_TimeBase | |||
static UInt64 sLastTime; | |||
#endif | |||
}; | |||
inline UInt64 CAHostTimeBase::GetTheCurrentTime() | |||
{ | |||
UInt64 theTime = 0; | |||
#if TARGET_OS_MAC | |||
theTime = mach_absolute_time(); | |||
#elif TARGET_OS_WIN32 | |||
LARGE_INTEGER theValue; | |||
QueryPerformanceCounter(&theValue); | |||
theTime = *((UInt64*)&theValue); | |||
#endif | |||
#if Track_Host_TimeBase | |||
if(sLastTime != 0) | |||
{ | |||
if(theTime <= sLastTime) | |||
{ | |||
DebugPrintf("CAHostTimeBase::GetTheCurrentTime: the current time is earlier than the last time, now: %qd, then: %qd", theTime, sLastTime); | |||
} | |||
sLastTime = theTime; | |||
} | |||
else | |||
{ | |||
sLastTime = theTime; | |||
} | |||
#endif | |||
return theTime; | |||
} | |||
inline UInt64 CAHostTimeBase::ConvertToNanos(UInt64 inHostTime) | |||
{ | |||
pthread_once(&sIsInited, Initialize); | |||
UInt64 theAnswer = MultiplyByRatio(inHostTime, sToNanosNumerator, sToNanosDenominator); | |||
#if CoreAudio_Debug | |||
if(((sToNanosNumerator > sToNanosDenominator) && (theAnswer < inHostTime)) || ((sToNanosDenominator > sToNanosNumerator) && (theAnswer > inHostTime))) | |||
{ | |||
DebugPrintf("CAHostTimeBase::ConvertToNanos: The conversion wrapped"); | |||
} | |||
#endif | |||
return theAnswer; | |||
} | |||
inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos) | |||
{ | |||
pthread_once(&sIsInited, Initialize); | |||
UInt64 theAnswer = MultiplyByRatio(inNanos, sToNanosDenominator, sToNanosNumerator); | |||
#if CoreAudio_Debug | |||
if(((sToNanosDenominator > sToNanosNumerator) && (theAnswer < inNanos)) || ((sToNanosNumerator > sToNanosDenominator) && (theAnswer > inNanos))) | |||
{ | |||
DebugPrintf("CAHostTimeBase::ConvertFromNanos: The conversion wrapped"); | |||
} | |||
#endif | |||
return theAnswer; | |||
} | |||
inline UInt64 CAHostTimeBase::GetCurrentTimeInNanos() | |||
{ | |||
return ConvertToNanos(GetTheCurrentTime()); | |||
} | |||
inline UInt64 CAHostTimeBase::AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime) | |||
{ | |||
UInt64 theAnswer; | |||
if(inStartTime <= inEndTime) | |||
{ | |||
theAnswer = inEndTime - inStartTime; | |||
} | |||
else | |||
{ | |||
theAnswer = inStartTime - inEndTime; | |||
} | |||
return ConvertToNanos(theAnswer); | |||
} | |||
inline SInt64 CAHostTimeBase::HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime) | |||
{ | |||
SInt64 theAnswer; | |||
SInt64 theSign = 1; | |||
if(inStartTime <= inEndTime) | |||
{ | |||
theAnswer = static_cast<SInt64>(inEndTime - inStartTime); | |||
} | |||
else | |||
{ | |||
theAnswer = static_cast<SInt64>(inStartTime - inEndTime); | |||
theSign = -1; | |||
} | |||
return theSign * static_cast<SInt64>(ConvertToNanos(static_cast<UInt64>(theAnswer))); | |||
} | |||
inline UInt64 CAHostTimeBase::MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator) | |||
{ | |||
#if TARGET_OS_MAC && TARGET_RT_64_BIT | |||
__uint128_t theAnswer = inMuliplicand; | |||
#else | |||
long double theAnswer = inMuliplicand; | |||
#endif | |||
if(inNumerator != inDenominator) | |||
{ | |||
theAnswer *= inNumerator; | |||
theAnswer /= inDenominator; | |||
} | |||
return static_cast<UInt64>(theAnswer); | |||
} | |||
#endif |
@@ -1,68 +0,0 @@ | |||
/* | |||
File: CAMath.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 __CAMath_h__ | |||
#define __CAMath_h__ | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#else | |||
#include <CoreAudioTypes.h> | |||
#endif | |||
inline bool fiszero(Float64 f) { return (f == 0.); } | |||
inline bool fiszero(Float32 f) { return (f == 0.f); } | |||
inline bool fnonzero(Float64 f) { return !fiszero(f); } | |||
inline bool fnonzero(Float32 f) { return !fiszero(f); } | |||
inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; } | |||
inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; } | |||
inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); } | |||
inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); } | |||
#endif // __CAMath_h__ |
@@ -1,345 +0,0 @@ | |||
/* | |||
File: CAMutex.cpp | |||
Abstract: CAMutex.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 "CAMutex.h" | |||
#if TARGET_OS_MAC | |||
#include <errno.h> | |||
#endif | |||
// PublicUtility Includes | |||
#include "CADebugMacros.h" | |||
#include "CAException.h" | |||
#include "CAHostTimeBase.h" | |||
//================================================================================================== | |||
// Logging | |||
//================================================================================================== | |||
#if CoreAudio_Debug | |||
// #define Log_Ownership 1 | |||
// #define Log_Errors 1 | |||
// #define Log_LongLatencies 1 | |||
// #define LongLatencyThreshholdNS 1000000ULL // nanoseconds | |||
#endif | |||
//================================================================================================== | |||
// CAMutex | |||
//================================================================================================== | |||
CAMutex::CAMutex(const char* inName) | |||
: | |||
mName(inName), | |||
mOwner(0) | |||
{ | |||
#if TARGET_OS_MAC | |||
OSStatus theError = pthread_mutex_init(&mMutex, NULL); | |||
ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex"); | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); | |||
#endif | |||
#elif TARGET_OS_WIN32 | |||
mMutex = CreateMutex(NULL, false, NULL); | |||
ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex."); | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); | |||
#endif | |||
#endif | |||
} | |||
CAMutex::~CAMutex() | |||
{ | |||
#if TARGET_OS_MAC | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::~CAMutex: destroying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); | |||
#endif | |||
pthread_mutex_destroy(&mMutex); | |||
#elif TARGET_OS_WIN32 | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::~CAMutex: destroying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); | |||
#endif | |||
if(mMutex != NULL) | |||
{ | |||
CloseHandle(mMutex); | |||
} | |||
#endif | |||
} | |||
bool CAMutex::Lock() | |||
{ | |||
bool theAnswer = false; | |||
#if TARGET_OS_MAC | |||
pthread_t theCurrentThread = pthread_self(); | |||
if(!pthread_equal(theCurrentThread, mOwner)) | |||
{ | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p is locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); | |||
#endif | |||
#if Log_LongLatencies | |||
UInt64 lockTryTime = CAHostTimeBase::GetCurrentTimeInNanos(); | |||
#endif | |||
OSStatus theError = pthread_mutex_lock(&mMutex); | |||
ThrowIf(theError != 0, CAException(theError), "CAMutex::Lock: Could not lock the mutex"); | |||
mOwner = theCurrentThread; | |||
theAnswer = true; | |||
#if Log_LongLatencies | |||
UInt64 lockAcquireTime = CAHostTimeBase::GetCurrentTimeInNanos(); | |||
if (lockAcquireTime - lockTryTime >= LongLatencyThresholdNS) | |||
DebugPrintfRtn(DebugPrintfFileComma "Thread %p took %.6fs to acquire the lock %s\n", theCurrentThread, (lockAcquireTime - lockTryTime) * 1.0e-9 /* nanos to seconds */, mName); | |||
#endif | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p has locked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); | |||
#endif | |||
} | |||
#elif TARGET_OS_WIN32 | |||
if(mOwner != GetCurrentThreadId()) | |||
{ | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu is locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
OSStatus theError = WaitForSingleObject(mMutex, INFINITE); | |||
ThrowIfError(theError, CAException(theError), "CAMutex::Lock: could not lock the mutex"); | |||
mOwner = GetCurrentThreadId(); | |||
theAnswer = true; | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
} | |||
#endif | |||
return theAnswer; | |||
} | |||
void CAMutex::Unlock() | |||
{ | |||
#if TARGET_OS_MAC | |||
if(pthread_equal(pthread_self(), mOwner)) | |||
{ | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p is unlocking %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); | |||
#endif | |||
mOwner = 0; | |||
OSStatus theError = pthread_mutex_unlock(&mMutex); | |||
ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex"); | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p has unlocked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); | |||
#endif | |||
} | |||
else | |||
{ | |||
DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); | |||
} | |||
#elif TARGET_OS_WIN32 | |||
if(mOwner == GetCurrentThreadId()) | |||
{ | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
mOwner = 0; | |||
bool wasReleased = ReleaseMutex(mMutex); | |||
ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex"); | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
} | |||
else | |||
{ | |||
DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); | |||
} | |||
#endif | |||
} | |||
bool CAMutex::Try(bool& outWasLocked) | |||
{ | |||
bool theAnswer = false; | |||
outWasLocked = false; | |||
#if TARGET_OS_MAC | |||
pthread_t theCurrentThread = pthread_self(); | |||
if(!pthread_equal(theCurrentThread, mOwner)) | |||
{ | |||
// this means the current thread doesn't already own the lock | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); | |||
#endif | |||
// go ahead and call trylock to see if we can lock it. | |||
int theError = pthread_mutex_trylock(&mMutex); | |||
if(theError == 0) | |||
{ | |||
// return value of 0 means we successfully locked the lock | |||
mOwner = theCurrentThread; | |||
theAnswer = true; | |||
outWasLocked = true; | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); | |||
#endif | |||
} | |||
else if(theError == EBUSY) | |||
{ | |||
// return value of EBUSY means that the lock was already locked by another thread | |||
theAnswer = false; | |||
outWasLocked = false; | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); | |||
#endif | |||
} | |||
else | |||
{ | |||
// any other return value means something really bad happenned | |||
ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed"); | |||
} | |||
} | |||
else | |||
{ | |||
// this means the current thread already owns the lock | |||
theAnswer = true; | |||
outWasLocked = false; | |||
} | |||
#elif TARGET_OS_WIN32 | |||
if(mOwner != GetCurrentThreadId()) | |||
{ | |||
// this means the current thread doesn't own the lock | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
// try to acquire the mutex | |||
OSStatus theError = WaitForSingleObject(mMutex, 0); | |||
if(theError == WAIT_OBJECT_0) | |||
{ | |||
// this means we successfully locked the lock | |||
mOwner = GetCurrentThreadId(); | |||
theAnswer = true; | |||
outWasLocked = true; | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
} | |||
else if(theError == WAIT_TIMEOUT) | |||
{ | |||
// this means that the lock was already locked by another thread | |||
theAnswer = false; | |||
outWasLocked = false; | |||
#if Log_Ownership | |||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); | |||
#endif | |||
} | |||
else | |||
{ | |||
// any other return value means something really bad happenned | |||
ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed"); | |||
} | |||
} | |||
else | |||
{ | |||
// this means the current thread already owns the lock | |||
theAnswer = true; | |||
outWasLocked = false; | |||
} | |||
#endif | |||
return theAnswer; | |||
} | |||
bool CAMutex::IsFree() const | |||
{ | |||
return mOwner == 0; | |||
} | |||
bool CAMutex::IsOwnedByCurrentThread() const | |||
{ | |||
bool theAnswer = true; | |||
#if TARGET_OS_MAC | |||
theAnswer = pthread_equal(pthread_self(), mOwner); | |||
#elif TARGET_OS_WIN32 | |||
theAnswer = (mOwner == GetCurrentThreadId()); | |||
#endif | |||
return theAnswer; | |||
} | |||
CAMutex::Unlocker::Unlocker(CAMutex& inMutex) | |||
: mMutex(inMutex), | |||
mNeedsLock(false) | |||
{ | |||
Assert(mMutex.IsOwnedByCurrentThread(), "Major problem: Unlocker attempted to unlock a mutex not owned by the current thread!"); | |||
mMutex.Unlock(); | |||
mNeedsLock = true; | |||
} | |||
CAMutex::Unlocker::~Unlocker() | |||
{ | |||
if(mNeedsLock) | |||
{ | |||
mMutex.Lock(); | |||
} | |||
} |
@@ -1,163 +0,0 @@ | |||
/* | |||
File: CAMutex.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 __CAMutex_h__ | |||
#define __CAMutex_h__ | |||
//================================================================================================== | |||
// Includes | |||
//================================================================================================== | |||
// System Includes | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#else | |||
#include <CoreAudioTypes.h> | |||
#endif | |||
#if TARGET_OS_MAC | |||
#include <pthread.h> | |||
#elif TARGET_OS_WIN32 | |||
#include <windows.h> | |||
#else | |||
#error Unsupported operating system | |||
#endif | |||
//================================================================================================== | |||
// A recursive mutex. | |||
//================================================================================================== | |||
class CAMutex | |||
{ | |||
// Construction/Destruction | |||
public: | |||
CAMutex(const char* inName); | |||
virtual ~CAMutex(); | |||
// Actions | |||
public: | |||
virtual bool Lock(); | |||
virtual void Unlock(); | |||
virtual bool Try(bool& outWasLocked); // returns true if lock is free, false if not | |||
virtual bool IsFree() const; | |||
virtual bool IsOwnedByCurrentThread() const; | |||
// Implementation | |||
protected: | |||
const char* mName; | |||
#if TARGET_OS_MAC | |||
pthread_t mOwner; | |||
pthread_mutex_t mMutex; | |||
#elif TARGET_OS_WIN32 | |||
UInt32 mOwner; | |||
HANDLE mMutex; | |||
#endif | |||
// Helper class to manage taking and releasing recursively | |||
public: | |||
class Locker | |||
{ | |||
// Construction/Destruction | |||
public: | |||
Locker(CAMutex& inMutex) : mMutex(&inMutex), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); } | |||
Locker(CAMutex* inMutex) : mMutex(inMutex), mNeedsRelease(false) { mNeedsRelease = (mMutex != NULL && mMutex->Lock()); } | |||
// in this case the mutex can be null | |||
~Locker() { if(mNeedsRelease) { mMutex->Unlock(); } } | |||
private: | |||
Locker(const Locker&); | |||
Locker& operator=(const Locker&); | |||
// Implementation | |||
private: | |||
CAMutex* mMutex; | |||
bool mNeedsRelease; | |||
}; | |||
// Unlocker | |||
class Unlocker | |||
{ | |||
public: | |||
Unlocker(CAMutex& inMutex); | |||
~Unlocker(); | |||
private: | |||
CAMutex& mMutex; | |||
bool mNeedsLock; | |||
// Hidden definitions of copy ctor, assignment operator | |||
Unlocker(const Unlocker& copy); // Not implemented | |||
Unlocker& operator=(const Unlocker& copy); // Not implemented | |||
}; | |||
// you can use this with Try - if you take the lock in try, pass in the outWasLocked var | |||
class Tryer { | |||
// Construction/Destruction | |||
public: | |||
Tryer (CAMutex &mutex) : mMutex(mutex), mNeedsRelease(false), mHasLock(false) { mHasLock = mMutex.Try (mNeedsRelease); } | |||
~Tryer () { if (mNeedsRelease) mMutex.Unlock(); } | |||
bool HasLock () const { return mHasLock; } | |||
private: | |||
Tryer(const Tryer&); | |||
Tryer& operator=(const Tryer&); | |||
// Implementation | |||
private: | |||
CAMutex & mMutex; | |||
bool mNeedsRelease; | |||
bool mHasLock; | |||
}; | |||
}; | |||
#endif // __CAMutex_h__ |
@@ -1,97 +0,0 @@ | |||
/* | |||
File: CAReferenceCounted.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 __CAReferenceCounted_h__ | |||
#define __CAReferenceCounted_h__ | |||
#include "CAAtomic.h" | |||
// base class for reference-counted objects | |||
class CAReferenceCounted { | |||
public: | |||
CAReferenceCounted() : mRefCount(1) {} | |||
void retain() { CAAtomicIncrement32(&mRefCount); } | |||
void release() | |||
{ | |||
SInt32 rc = CAAtomicDecrement32(&mRefCount); | |||
if (rc == 0) { | |||
releaseObject(); | |||
} | |||
} | |||
class Retainer { | |||
public: | |||
Retainer(CAReferenceCounted *obj) : mObject(obj) { mObject->retain(); } | |||
~Retainer() { mObject->release(); } | |||
private: | |||
CAReferenceCounted * mObject; | |||
}; | |||
protected: | |||
virtual ~CAReferenceCounted() { } | |||
virtual void releaseObject () | |||
{ | |||
delete this; | |||
} | |||
#if DEBUG | |||
public: | |||
#endif | |||
SInt32 GetReferenceCount() const { return mRefCount; } | |||
private: | |||
SInt32 mRefCount; | |||
CAReferenceCounted(const CAReferenceCounted &a); | |||
CAReferenceCounted &operator=(const CAReferenceCounted &a); | |||
}; | |||
#endif // __CAReferenceCounted_h__ |
@@ -1,879 +0,0 @@ | |||
/* | |||
File: CAStreamBasicDescription.cpp | |||
Abstract: CAStreamBasicDescription.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 "CAStreamBasicDescription.h" | |||
#include "CAMath.h" | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreFoundation/CFByteOrder.h> | |||
#else | |||
#include <CFByteOrder.h> | |||
#endif | |||
#pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it | |||
char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize) | |||
{ | |||
if (bufsize > 0) { | |||
char *p = writeLocation, *pend = writeLocation + bufsize; | |||
union { UInt32 i; unsigned char str[4]; } u; | |||
unsigned char *q = u.str; | |||
u.i = CFSwapInt32HostToBig(t); | |||
bool hasNonPrint = false; | |||
for (int i = 0; i < 4; ++i) { | |||
if (!(isprint(*q) && *q != '\\')) { | |||
hasNonPrint = true; | |||
break; | |||
} | |||
q++; | |||
} | |||
q = u.str; | |||
if (hasNonPrint) | |||
p += snprintf (p, pend - p, "0x"); | |||
else if (p < pend) | |||
*p++ = '\''; | |||
for (int i = 0; i < 4 && p < pend; ++i) { | |||
if (hasNonPrint) { | |||
p += snprintf(p, pend - p, "%02X", *q++); | |||
} else { | |||
*p++ = *q++; | |||
} | |||
} | |||
if (!hasNonPrint && p < pend) | |||
*p++ = '\''; | |||
if (p >= pend) p -= 1; | |||
*p = '\0'; | |||
} | |||
return writeLocation; | |||
} | |||
const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |||
CAStreamBasicDescription::CAStreamBasicDescription() | |||
{ | |||
memset (this, 0, sizeof(AudioStreamBasicDescription)); | |||
} | |||
CAStreamBasicDescription::CAStreamBasicDescription(const AudioStreamBasicDescription &desc) | |||
{ | |||
SetFrom(desc); | |||
} | |||
CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID, | |||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, | |||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, | |||
UInt32 inBitsPerChannel, UInt32 inFormatFlags) | |||
{ | |||
mSampleRate = inSampleRate; | |||
mFormatID = inFormatID; | |||
mBytesPerPacket = inBytesPerPacket; | |||
mFramesPerPacket = inFramesPerPacket; | |||
mBytesPerFrame = inBytesPerFrame; | |||
mChannelsPerFrame = inChannelsPerFrame; | |||
mBitsPerChannel = inBitsPerChannel; | |||
mFormatFlags = inFormatFlags; | |||
mReserved = 0; | |||
} | |||
char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize, bool brief /*=false*/) const | |||
{ | |||
int bufsize = (int)_bufsize; // must be signed to protect against overflow | |||
char *theBuffer = buf; | |||
int nc; | |||
char formatID[24]; | |||
CAStringForOSType(mFormatID, formatID, sizeof(formatID)); | |||
if (brief) { | |||
CommonPCMFormat com; | |||
bool interleaved; | |||
if (IdentifyCommonPCMFormat(com, &interleaved) && com != kPCMFormatOther) { | |||
const char *desc; | |||
switch (com) { | |||
case kPCMFormatInt16: | |||
desc = "Int16"; | |||
break; | |||
case kPCMFormatFixed824: | |||
desc = "Int8.24"; | |||
break; | |||
case kPCMFormatFloat32: | |||
desc = "Float32"; | |||
break; | |||
case kPCMFormatFloat64: | |||
desc = "Float64"; | |||
break; | |||
default: | |||
desc = NULL; | |||
break; | |||
} | |||
if (desc) { | |||
const char *inter =""; | |||
if (mChannelsPerFrame > 1) | |||
inter = !interleaved ? ", non-inter" : ", inter"; | |||
snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s%s", (int)mChannelsPerFrame, mSampleRate, desc, inter); | |||
return theBuffer; | |||
} | |||
} | |||
if (mChannelsPerFrame == 0 && mSampleRate == 0.0 && mFormatID == 0) { | |||
snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz", (int)mChannelsPerFrame, mSampleRate); | |||
return theBuffer; | |||
} | |||
} | |||
nc = snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags); | |||
buf += nc; if ((bufsize -= nc) <= 0) goto exit; | |||
if (mFormatID == kAudioFormatLinearPCM) { | |||
bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat); | |||
int wordSize = static_cast<int>(SampleWordSize()); | |||
const char *endian = (wordSize > 1) ? | |||
((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : ""; | |||
const char *sign = isInt ? | |||
((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : ""; | |||
const char *floatInt = isInt ? "integer" : "float"; | |||
char packed[32]; | |||
if (wordSize > 0 && PackednessIsSignificant()) { | |||
if (mFormatFlags & kLinearPCMFormatFlagIsPacked) | |||
snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize); | |||
else | |||
snprintf(packed, sizeof(packed), "unpacked in %d bytes", wordSize); | |||
} else | |||
packed[0] = '\0'; | |||
const char *align = (wordSize > 0 && AlignmentIsSignificant()) ? | |||
((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : ""; | |||
const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : ""; | |||
const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : ""; | |||
char bitdepth[20]; | |||
int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; | |||
if (fracbits > 0) | |||
snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits); | |||
else | |||
snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel); | |||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%s-bit%s%s %s%s%s%s%s", | |||
bitdepth, endian, sign, floatInt, | |||
commaSpace, packed, align, deinter); | |||
// buf += nc; if ((bufsize -= nc) <= 0) goto exit; | |||
} else if (mFormatID == kAudioFormatAppleLossless) { | |||
int sourceBits = 0; | |||
switch (mFormatFlags) | |||
{ | |||
case 1: // kAppleLosslessFormatFlag_16BitSourceData | |||
sourceBits = 16; | |||
break; | |||
case 2: // kAppleLosslessFormatFlag_20BitSourceData | |||
sourceBits = 20; | |||
break; | |||
case 3: // kAppleLosslessFormatFlag_24BitSourceData | |||
sourceBits = 24; | |||
break; | |||
case 4: // kAppleLosslessFormatFlag_32BitSourceData | |||
sourceBits = 32; | |||
break; | |||
} | |||
if (sourceBits) | |||
nc = snprintf(buf, static_cast<size_t>(bufsize), "from %d-bit source, ", sourceBits); | |||
else | |||
nc = snprintf(buf, static_cast<size_t>(bufsize), "from UNKNOWN source bit depth, "); | |||
buf += nc; if ((bufsize -= nc) <= 0) goto exit; | |||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%d frames/packet", (int)mFramesPerPacket); | |||
// buf += nc; if ((bufsize -= nc) <= 0) goto exit; | |||
} | |||
else | |||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame", | |||
(int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame); | |||
exit: | |||
return theBuffer; | |||
} | |||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription) | |||
{ | |||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format | |||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) | |||
{ | |||
// the canonical linear PCM format | |||
ioDescription.mFormatFlags = kAudioFormatFlagsCanonical; | |||
ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; | |||
ioDescription.mFramesPerPacket = 1; | |||
ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; | |||
ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType); | |||
} | |||
} | |||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription) | |||
{ | |||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format | |||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) | |||
{ | |||
// the canonical linear PCM format | |||
ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; | |||
if(inNativeEndian) | |||
{ | |||
#if TARGET_RT_BIG_ENDIAN | |||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian; | |||
#endif | |||
} | |||
else | |||
{ | |||
#if TARGET_RT_LITTLE_ENDIAN | |||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian; | |||
#endif | |||
} | |||
ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; | |||
ioDescription.mFramesPerPacket = 1; | |||
ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; | |||
ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType); | |||
} | |||
} | |||
void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription) | |||
{ | |||
ioDescription.mSampleRate = 0; | |||
ioDescription.mFormatID = 0; | |||
ioDescription.mBytesPerPacket = 0; | |||
ioDescription.mFramesPerPacket = 0; | |||
ioDescription.mBytesPerFrame = 0; | |||
ioDescription.mChannelsPerFrame = 0; | |||
ioDescription.mBitsPerChannel = 0; | |||
ioDescription.mFormatFlags = 0; | |||
} | |||
void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription) | |||
{ | |||
if(fiszero(ioDescription.mSampleRate)) | |||
{ | |||
ioDescription.mSampleRate = inTemplateDescription.mSampleRate; | |||
} | |||
if(ioDescription.mFormatID == 0) | |||
{ | |||
ioDescription.mFormatID = inTemplateDescription.mFormatID; | |||
} | |||
if(ioDescription.mFormatFlags == 0) | |||
{ | |||
ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags; | |||
} | |||
if(ioDescription.mBytesPerPacket == 0) | |||
{ | |||
ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket; | |||
} | |||
if(ioDescription.mFramesPerPacket == 0) | |||
{ | |||
ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket; | |||
} | |||
if(ioDescription.mBytesPerFrame == 0) | |||
{ | |||
ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame; | |||
} | |||
if(ioDescription.mChannelsPerFrame == 0) | |||
{ | |||
ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame; | |||
} | |||
if(ioDescription.mBitsPerChannel == 0) | |||
{ | |||
ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel; | |||
} | |||
} | |||
void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate) | |||
{ | |||
if(inIncludeSampleRate) | |||
{ | |||
int theCharactersWritten = snprintf(outName, inMaxNameLength, "%.0f ", inDescription.mSampleRate); | |||
outName += theCharactersWritten; | |||
inMaxNameLength -= static_cast<UInt32>(theCharactersWritten); | |||
} | |||
switch(inDescription.mFormatID) | |||
{ | |||
case kAudioFormatLinearPCM: | |||
{ | |||
const char* theEndianString = NULL; | |||
if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) | |||
{ | |||
#if TARGET_RT_LITTLE_ENDIAN | |||
theEndianString = "Big Endian"; | |||
#endif | |||
} | |||
else | |||
{ | |||
#if TARGET_RT_BIG_ENDIAN | |||
theEndianString = "Little Endian"; | |||
#endif | |||
} | |||
const char* theKindString = NULL; | |||
if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0) | |||
{ | |||
theKindString = (inAbbreviate ? "Float" : "Floating Point"); | |||
} | |||
else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) | |||
{ | |||
theKindString = (inAbbreviate ? "SInt" : "Signed Integer"); | |||
} | |||
else | |||
{ | |||
theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer"); | |||
} | |||
const char* thePackingString = NULL; | |||
if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0) | |||
{ | |||
if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) | |||
{ | |||
thePackingString = "High"; | |||
} | |||
else | |||
{ | |||
thePackingString = "Low"; | |||
} | |||
} | |||
const char* theMixabilityString = NULL; | |||
if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0) | |||
{ | |||
theMixabilityString = "Mixable"; | |||
} | |||
else | |||
{ | |||
theMixabilityString = "Unmixable"; | |||
} | |||
if(inAbbreviate) | |||
{ | |||
if(theEndianString != NULL) | |||
{ | |||
if(thePackingString != NULL) | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); | |||
} | |||
else | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel); | |||
} | |||
} | |||
else | |||
{ | |||
if(thePackingString != NULL) | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8)); | |||
} | |||
else | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel); | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
if(theEndianString != NULL) | |||
{ | |||
if(thePackingString != NULL) | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); | |||
} | |||
else | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString); | |||
} | |||
} | |||
else | |||
{ | |||
if(thePackingString != NULL) | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); | |||
} | |||
else | |||
{ | |||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString); | |||
} | |||
} | |||
} | |||
} | |||
break; | |||
case kAudioFormatAC3: | |||
strlcpy(outName, "AC-3", sizeof(outName)); | |||
break; | |||
case kAudioFormat60958AC3: | |||
strlcpy(outName, "AC-3 for SPDIF", sizeof(outName)); | |||
break; | |||
default: | |||
CACopy4CCToCString(outName, inDescription.mFormatID); | |||
break; | |||
}; | |||
} | |||
#if CoreAudio_Debug | |||
#include "CALogMacros.h" | |||
void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc) | |||
{ | |||
PrintFloat (" Sample Rate: ", inDesc.mSampleRate); | |||
Print4CharCode (" Format ID: ", inDesc.mFormatID); | |||
PrintHex (" Format Flags: ", inDesc.mFormatFlags); | |||
PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket); | |||
PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket); | |||
PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame); | |||
PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame); | |||
PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel); | |||
} | |||
#endif | |||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) | |||
{ | |||
bool theAnswer = false; | |||
bool isDone = false; | |||
// note that if either side is 0, that field is skipped | |||
// format ID is the first order sort | |||
if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0))) | |||
{ | |||
if(x.mFormatID != y.mFormatID) | |||
{ | |||
// formats are sorted numerically except that linear | |||
// PCM is always first | |||
if(x.mFormatID == kAudioFormatLinearPCM) | |||
{ | |||
theAnswer = true; | |||
} | |||
else if(y.mFormatID == kAudioFormatLinearPCM) | |||
{ | |||
theAnswer = false; | |||
} | |||
else | |||
{ | |||
theAnswer = x.mFormatID < y.mFormatID; | |||
} | |||
isDone = true; | |||
} | |||
} | |||
// mixable is always better than non-mixable for linear PCM and should be the second order sort item | |||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) | |||
{ | |||
if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0)) | |||
{ | |||
theAnswer = true; | |||
isDone = true; | |||
} | |||
else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0)) | |||
{ | |||
theAnswer = false; | |||
isDone = true; | |||
} | |||
} | |||
// floating point vs integer for linear PCM only | |||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) | |||
{ | |||
if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat)) | |||
{ | |||
// floating point is better than integer | |||
theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat; | |||
isDone = true; | |||
} | |||
} | |||
// bit depth | |||
if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0))) | |||
{ | |||
if(x.mBitsPerChannel != y.mBitsPerChannel) | |||
{ | |||
// deeper bit depths are higher quality | |||
theAnswer = x.mBitsPerChannel < y.mBitsPerChannel; | |||
isDone = true; | |||
} | |||
} | |||
// sample rate | |||
if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate)) | |||
{ | |||
if(fnotequal(x.mSampleRate, y.mSampleRate)) | |||
{ | |||
// higher sample rates are higher quality | |||
theAnswer = x.mSampleRate < y.mSampleRate; | |||
isDone = true; | |||
} | |||
} | |||
// number of channels | |||
if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0))) | |||
{ | |||
if(x.mChannelsPerFrame != y.mChannelsPerFrame) | |||
{ | |||
// more channels is higher quality | |||
theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame; | |||
//isDone = true; | |||
} | |||
} | |||
return theAnswer; | |||
} | |||
void CAStreamBasicDescription::ModifyFormatFlagsForMatching(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y, UInt32& xFlags, UInt32& yFlags, bool converterOnly ) | |||
{ | |||
// match wildcards | |||
if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) | |||
{ | |||
// Obliterate all flags. | |||
xFlags = yFlags = 0; | |||
return; | |||
} | |||
if (x.mFormatID == kAudioFormatLinearPCM) { | |||
// knock off the all clear flag | |||
xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; | |||
yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; | |||
// if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. | |||
if (xFlags & yFlags & kAudioFormatFlagIsPacked) { | |||
xFlags = xFlags & ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh); | |||
yFlags = yFlags & ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh); | |||
} | |||
// if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. | |||
if (xFlags & yFlags & kAudioFormatFlagIsFloat) { | |||
xFlags = xFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger); | |||
yFlags = yFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger); | |||
} | |||
// if the bit depth is 8 bits or less and the format is packed, we don't care about endianness | |||
if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) | |||
{ | |||
xFlags = xFlags & ~static_cast<UInt32>(kAudioFormatFlagIsBigEndian); | |||
} | |||
if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) | |||
{ | |||
yFlags = yFlags & ~static_cast<UInt32>(kAudioFormatFlagIsBigEndian); | |||
} | |||
// if the number of channels is 1, we don't care about non-interleavedness | |||
if (x.mChannelsPerFrame == 1 && y.mChannelsPerFrame == 1) { | |||
xFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsNonInterleaved); | |||
yFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsNonInterleaved); | |||
} | |||
if (converterOnly) { | |||
CAStreamBasicDescription cas_x = CAStreamBasicDescription(x); | |||
CAStreamBasicDescription cas_y = CAStreamBasicDescription(y); | |||
if (!cas_x.PackednessIsSignificant() && !cas_y.PackednessIsSignificant()) { | |||
xFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsPacked); | |||
yFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsPacked); | |||
} | |||
if (!cas_x.AlignmentIsSignificant() && !cas_y.AlignmentIsSignificant()) { | |||
xFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh); | |||
yFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh); | |||
} | |||
// We don't care about whether the streams are mixable in this case | |||
xFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonMixable); | |||
yFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonMixable); | |||
} | |||
} | |||
} | |||
static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) | |||
{ | |||
UInt32 xFlags = x.mFormatFlags; | |||
UInt32 yFlags = y.mFormatFlags; | |||
CAStreamBasicDescription::ModifyFormatFlagsForMatching(x, y, xFlags, yFlags, false); | |||
return xFlags == yFlags; | |||
} | |||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) | |||
{ | |||
// the semantics for equality are: | |||
// 1) Values must match exactly -- except for PCM format flags, see above. | |||
// 2) wildcard's are ignored in the comparison | |||
#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) | |||
return | |||
// check all but the format flags | |||
CAStreamBasicDescription::FlagIndependentEquivalence(x, y) | |||
// check the format flags | |||
&& MatchFormatFlags(x, y); | |||
} | |||
bool CAStreamBasicDescription::FlagIndependentEquivalence(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y) | |||
{ | |||
return | |||
// check the sample rate | |||
(fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate)) | |||
// check the format ids | |||
&& MATCH(mFormatID) | |||
// check the bytes per packet | |||
&& MATCH(mBytesPerPacket) | |||
// check the frames per packet | |||
&& MATCH(mFramesPerPacket) | |||
// check the bytes per frame | |||
&& MATCH(mBytesPerFrame) | |||
// check the channels per frame | |||
&& MATCH(mChannelsPerFrame) | |||
// check the channels per frame | |||
&& MATCH(mBitsPerChannel) ; | |||
} | |||
bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const | |||
{ | |||
if (interpretingWildcards) | |||
return *this == other; | |||
return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0; | |||
} | |||
bool CAStreamBasicDescription::IsFunctionallyEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y) | |||
{ | |||
UInt32 xFlags = x.mFormatFlags, yFlags = y.mFormatFlags; | |||
CAStreamBasicDescription::ModifyFormatFlagsForMatching(x, y, xFlags, yFlags, true); | |||
return | |||
// check all but the format flags | |||
CAStreamBasicDescription::FlagIndependentEquivalence(x, y) | |||
// check the format flags with converter focus | |||
&& (xFlags == yFlags); | |||
} | |||
bool SanityCheck(const AudioStreamBasicDescription& x) | |||
{ | |||
// This function returns false if there are sufficiently insane values in any field. | |||
// It is very conservative so even some very unlikely values will pass. | |||
// This is just meant to catch the case where the data from a file is corrupted. | |||
return | |||
(x.mSampleRate >= 0.) | |||
&& (x.mSampleRate < 3e6) // SACD sample rate is 2.8224 MHz | |||
&& (x.mBytesPerPacket < 1000000) | |||
&& (x.mFramesPerPacket < 1000000) | |||
&& (x.mBytesPerFrame < 1000000) | |||
&& (x.mChannelsPerFrame <= 1024) | |||
&& (x.mBitsPerChannel <= 1024) | |||
&& (x.mFormatID != 0) | |||
&& !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame)); | |||
} | |||
bool CAStreamBasicDescription::FromText(const char *inTextDesc, AudioStreamBasicDescription &fmt) | |||
{ | |||
const char *p = inTextDesc; | |||
memset(&fmt, 0, sizeof(fmt)); | |||
bool isPCM = true; // until proven otherwise | |||
UInt32 pcmFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; | |||
if (p[0] == '-') // previously we required a leading dash on PCM formats | |||
++p; | |||
if (p[0] == 'B' && p[1] == 'E') { | |||
pcmFlags |= kLinearPCMFormatFlagIsBigEndian; | |||
p += 2; | |||
} else if (p[0] == 'L' && p[1] == 'E') { | |||
p += 2; | |||
} else { | |||
// default is native-endian | |||
#if TARGET_RT_BIG_ENDIAN | |||
pcmFlags |= kLinearPCMFormatFlagIsBigEndian; | |||
#endif | |||
} | |||
if (p[0] == 'F') { | |||
pcmFlags = (pcmFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger)) | kAudioFormatFlagIsFloat; | |||
++p; | |||
} else { | |||
if (p[0] == 'U') { | |||
pcmFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger); | |||
++p; | |||
} | |||
if (p[0] == 'I') | |||
++p; | |||
else { | |||
// it's not PCM; presumably some other format (NOT VALIDATED; use AudioFormat for that) | |||
isPCM = false; | |||
p = inTextDesc; // go back to the beginning | |||
char buf[4] = { ' ',' ',' ',' ' }; | |||
for (int i = 0; i < 4; ++i) { | |||
if (*p != '\\') { | |||
if ((buf[i] = *p++) == '\0') { | |||
// special-case for 'aac' | |||
if (i != 3) return false; | |||
--p; // keep pointing at the terminating null | |||
buf[i] = ' '; | |||
break; | |||
} | |||
} else { | |||
// "\xNN" is a hex byte | |||
if (*++p != 'x') return false; | |||
int x; | |||
if (sscanf(++p, "%02X", &x) != 1) return false; | |||
buf[i] = static_cast<char>(x); | |||
p += 2; | |||
} | |||
} | |||
if (strchr("-@/#", buf[3])) { | |||
// further special-casing for 'aac' | |||
buf[3] = ' '; | |||
--p; | |||
} | |||
memcpy(&fmt.mFormatID, buf, 4); | |||
fmt.mFormatID = CFSwapInt32BigToHost(fmt.mFormatID); | |||
} | |||
} | |||
if (isPCM) { | |||
fmt.mFormatID = kAudioFormatLinearPCM; | |||
fmt.mFormatFlags = pcmFlags; | |||
fmt.mFramesPerPacket = 1; | |||
fmt.mChannelsPerFrame = 1; | |||
UInt32 bitdepth = 0, fracbits = 0; | |||
while (isdigit(*p)) | |||
bitdepth = 10 * bitdepth + static_cast<UInt32>(*p++ - '0'); | |||
if (*p == '.') { | |||
++p; | |||
if (!isdigit(*p)) { | |||
fprintf(stderr, "Expected fractional bits following '.'\n"); | |||
goto Bail; | |||
} | |||
while (isdigit(*p)) | |||
fracbits = 10 * fracbits + static_cast<UInt32>(*p++ - '0'); | |||
bitdepth += fracbits; | |||
fmt.mFormatFlags |= (fracbits << kLinearPCMFormatFlagsSampleFractionShift); | |||
} | |||
fmt.mBitsPerChannel = bitdepth; | |||
fmt.mBytesPerPacket = fmt.mBytesPerFrame = (bitdepth + 7) / 8; | |||
if (bitdepth & 7) { | |||
// assume unpacked. (packed odd bit depths are describable but not supported in AudioConverter.) | |||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsPacked); | |||
// alignment matters; default to high-aligned. use ':L_' for low. | |||
fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; | |||
} | |||
} | |||
if (*p == '@') { | |||
++p; | |||
while (isdigit(*p)) | |||
fmt.mSampleRate = 10 * fmt.mSampleRate + (*p++ - '0'); | |||
} | |||
if (*p == '/') { | |||
UInt32 flags = 0; | |||
while (true) { | |||
char c = *++p; | |||
if (c >= '0' && c <= '9') | |||
flags = (flags << 4) | static_cast<UInt32>(c - '0'); | |||
else if (c >= 'A' && c <= 'F') | |||
flags = (flags << 4) | static_cast<UInt32>(c - 'A' + 10); | |||
else if (c >= 'a' && c <= 'f') | |||
flags = (flags << 4) | static_cast<UInt32>(c - 'a' + 10); | |||
else break; | |||
} | |||
fmt.mFormatFlags = flags; | |||
} | |||
if (*p == '#') { | |||
++p; | |||
while (isdigit(*p)) | |||
fmt.mFramesPerPacket = 10 * fmt.mFramesPerPacket + static_cast<UInt32>(*p++ - '0'); | |||
} | |||
if (*p == ':') { | |||
++p; | |||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsPacked); | |||
if (*p == 'L') | |||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsAlignedHigh); | |||
else if (*p == 'H') | |||
fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; | |||
else | |||
goto Bail; | |||
++p; | |||
UInt32 bytesPerFrame = 0; | |||
while (isdigit(*p)) | |||
bytesPerFrame = 10 * bytesPerFrame + static_cast<UInt32>(*p++ - '0'); | |||
fmt.mBytesPerFrame = fmt.mBytesPerPacket = bytesPerFrame; | |||
} | |||
if (*p == ',') { | |||
++p; | |||
int ch = 0; | |||
while (isdigit(*p)) | |||
ch = 10 * ch + (*p++ - '0'); | |||
fmt.mChannelsPerFrame = static_cast<UInt32>(ch); | |||
if (*p == 'D') { | |||
++p; | |||
if (fmt.mFormatID != kAudioFormatLinearPCM) { | |||
fprintf(stderr, "non-interleaved flag invalid for non-PCM formats\n"); | |||
goto Bail; | |||
} | |||
fmt.mFormatFlags |= kAudioFormatFlagIsNonInterleaved; | |||
} else { | |||
if (*p == 'I') ++p; // default | |||
if (fmt.mFormatID == kAudioFormatLinearPCM) | |||
fmt.mBytesPerPacket = fmt.mBytesPerFrame *= static_cast<UInt32>(ch); | |||
} | |||
} | |||
if (*p != '\0') { | |||
fprintf(stderr, "extra characters at end of format string: %s\n", p); | |||
goto Bail; | |||
} | |||
return true; | |||
Bail: | |||
fprintf(stderr, "Invalid format string: %s\n", inTextDesc); | |||
fprintf(stderr, "Syntax of format strings is: \n"); | |||
return false; | |||
} | |||
const char *CAStreamBasicDescription::sTextParsingUsageString = | |||
"format[@sample_rate_hz][/format_flags][#frames_per_packet][:LHbytesPerFrame][,channelsDI].\n" | |||
"Format for PCM is [-][BE|LE]{F|I|UI}{bitdepth}; else a 4-char format code (e.g. aac, alac).\n"; |
@@ -1,424 +0,0 @@ | |||
/* | |||
File: CAStreamBasicDescription.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 __CAStreamBasicDescription_h__ | |||
#define __CAStreamBasicDescription_h__ | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreAudio/CoreAudioTypes.h> | |||
#include <CoreFoundation/CoreFoundation.h> | |||
#else | |||
#include "CoreAudioTypes.h" | |||
#include "CoreFoundation.h" | |||
#endif | |||
#include "CADebugMacros.h" | |||
#include <string.h> // for memset, memcpy | |||
#include <stdio.h> // for FILE * | |||
#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it | |||
extern char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize); | |||
// define Leopard specific symbols for backward compatibility if applicable | |||
#if COREAUDIOTYPES_VERSION < 1050 | |||
typedef Float32 AudioSampleType; | |||
enum { kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked }; | |||
#endif | |||
#if COREAUDIOTYPES_VERSION < 1051 | |||
typedef Float32 AudioUnitSampleType; | |||
enum { | |||
kLinearPCMFormatFlagsSampleFractionShift = 7, | |||
kLinearPCMFormatFlagsSampleFractionMask = (0x3F << kLinearPCMFormatFlagsSampleFractionShift), | |||
}; | |||
#endif | |||
// define the IsMixable format flag for all versions of the system | |||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) | |||
enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable }; | |||
#else | |||
enum { kIsNonMixableFlag = (1L << 6) }; | |||
#endif | |||
//============================================================================= | |||
// CAStreamBasicDescription | |||
// | |||
// This is a wrapper class for the AudioStreamBasicDescription struct. | |||
// It adds a number of convenience routines, but otherwise adds nothing | |||
// to the footprint of the original struct. | |||
//============================================================================= | |||
class CAStreamBasicDescription : | |||
public AudioStreamBasicDescription | |||
{ | |||
// Constants | |||
public: | |||
static const AudioStreamBasicDescription sEmpty; | |||
enum CommonPCMFormat { | |||
kPCMFormatOther = 0, | |||
kPCMFormatFloat32 = 1, | |||
kPCMFormatInt16 = 2, | |||
kPCMFormatFixed824 = 3, | |||
kPCMFormatFloat64 = 4 | |||
}; | |||
// Construction/Destruction | |||
public: | |||
CAStreamBasicDescription(); | |||
CAStreamBasicDescription(const AudioStreamBasicDescription &desc); | |||
CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID, | |||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, | |||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, | |||
UInt32 inBitsPerChannel, UInt32 inFormatFlags); | |||
CAStreamBasicDescription( double inSampleRate, UInt32 inNumChannels, CommonPCMFormat pcmf, bool inIsInterleaved) { | |||
unsigned wordsize; | |||
mSampleRate = inSampleRate; | |||
mFormatID = kAudioFormatLinearPCM; | |||
mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; | |||
mFramesPerPacket = 1; | |||
mChannelsPerFrame = inNumChannels; | |||
mBytesPerFrame = mBytesPerPacket = 0; | |||
mReserved = 0; | |||
switch (pcmf) { | |||
default: | |||
return; | |||
case kPCMFormatFloat32: | |||
wordsize = 4; | |||
mFormatFlags |= kAudioFormatFlagIsFloat; | |||
break; | |||
case kPCMFormatFloat64: | |||
wordsize = 8; | |||
mFormatFlags |= kAudioFormatFlagIsFloat; | |||
break; | |||
case kPCMFormatInt16: | |||
wordsize = 2; | |||
mFormatFlags |= kAudioFormatFlagIsSignedInteger; | |||
break; | |||
case kPCMFormatFixed824: | |||
wordsize = 4; | |||
mFormatFlags |= kAudioFormatFlagIsSignedInteger | (24 << kLinearPCMFormatFlagsSampleFractionShift); | |||
break; | |||
} | |||
mBitsPerChannel = wordsize * 8; | |||
if (inIsInterleaved) | |||
mBytesPerFrame = mBytesPerPacket = wordsize * inNumChannels; | |||
else { | |||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved; | |||
mBytesPerFrame = mBytesPerPacket = wordsize; | |||
} | |||
} | |||
// Assignment | |||
CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; } | |||
void SetFrom(const AudioStreamBasicDescription &desc) | |||
{ | |||
memcpy(this, &desc, sizeof(AudioStreamBasicDescription)); | |||
} | |||
bool FromText(const char *inTextDesc) { return FromText(inTextDesc, *this); } | |||
static bool FromText(const char *inTextDesc, AudioStreamBasicDescription &outDesc); | |||
// return true if parsing was successful | |||
static const char *sTextParsingUsageString; | |||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |||
// | |||
// interrogation | |||
bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; } | |||
bool PackednessIsSignificant() const | |||
{ | |||
Assert(IsPCM(), "PackednessIsSignificant only applies for PCM"); | |||
return (SampleWordSize() << 3) != mBitsPerChannel; | |||
} | |||
bool AlignmentIsSignificant() const | |||
{ | |||
return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0; | |||
} | |||
bool IsInterleaved() const | |||
{ | |||
return !(mFormatFlags & kAudioFormatFlagIsNonInterleaved); | |||
} | |||
bool IsSignedInteger() const | |||
{ | |||
return IsPCM() && (mFormatFlags & kAudioFormatFlagIsSignedInteger); | |||
} | |||
bool IsFloat() const | |||
{ | |||
return IsPCM() && (mFormatFlags & kAudioFormatFlagIsFloat); | |||
} | |||
bool IsNativeEndian() const | |||
{ | |||
return (mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian; | |||
} | |||
// for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these: | |||
UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; } | |||
UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; } | |||
UInt32 NumberChannels() const { return mChannelsPerFrame; } | |||
UInt32 SampleWordSize() const { | |||
return (mBytesPerFrame > 0 && NumberInterleavedChannels()) ? mBytesPerFrame / NumberInterleavedChannels() : 0; | |||
} | |||
UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; } | |||
UInt32 BytesToFrames(UInt32 nbytes) const { | |||
Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames"); | |||
return nbytes / mBytesPerFrame; | |||
} | |||
bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const | |||
{ | |||
return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved(); | |||
} | |||
bool IdentifyCommonPCMFormat(CommonPCMFormat &outFormat, bool *outIsInterleaved=NULL) const | |||
{ // return true if it's a valid PCM format. | |||
outFormat = kPCMFormatOther; | |||
// trap out patently invalid formats. | |||
if (mFormatID != kAudioFormatLinearPCM || mFramesPerPacket != 1 || mBytesPerFrame != mBytesPerPacket || mBitsPerChannel/8 > mBytesPerFrame || mChannelsPerFrame == 0) | |||
return false; | |||
bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; | |||
if (outIsInterleaved != NULL) *outIsInterleaved = interleaved; | |||
unsigned wordsize = mBytesPerFrame; | |||
if (interleaved) { | |||
if (wordsize % mChannelsPerFrame != 0) return false; | |||
wordsize /= mChannelsPerFrame; | |||
} | |||
if ((mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian | |||
&& wordsize * 8 == mBitsPerChannel) { | |||
// packed and native endian, good | |||
if (mFormatFlags & kLinearPCMFormatFlagIsFloat) { | |||
// float: reject nonsense bits | |||
if (mFormatFlags & (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagsSampleFractionMask)) | |||
return false; | |||
if (wordsize == 4) | |||
outFormat = kPCMFormatFloat32; | |||
if (wordsize == 8) | |||
outFormat = kPCMFormatFloat64; | |||
} else if (mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) { | |||
// signed int | |||
unsigned fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; | |||
if (wordsize == 4 && fracbits == 24) | |||
outFormat = kPCMFormatFixed824; | |||
else if (wordsize == 2 && fracbits == 0) | |||
outFormat = kPCMFormatInt16; | |||
} | |||
} | |||
return true; | |||
} | |||
bool IsCommonFloat32(bool *outIsInterleaved=NULL) const { | |||
CommonPCMFormat fmt; | |||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat32; | |||
} | |||
bool IsCommonFloat64(bool *outIsInterleaved=NULL) const { | |||
CommonPCMFormat fmt; | |||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat64; | |||
} | |||
bool IsCommonFixed824(bool *outIsInterleaved=NULL) const { | |||
CommonPCMFormat fmt; | |||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFixed824; | |||
} | |||
bool IsCommonInt16(bool *outIsInterleaved=NULL) const { | |||
CommonPCMFormat fmt; | |||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatInt16; | |||
} | |||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |||
// | |||
// manipulation | |||
void SetCanonical(UInt32 nChannels, bool interleaved) | |||
// note: leaves sample rate untouched | |||
{ | |||
mFormatID = kAudioFormatLinearPCM; | |||
UInt32 sampleSize = SizeOf32(AudioSampleType); | |||
mFormatFlags = kAudioFormatFlagsCanonical; | |||
mBitsPerChannel = 8 * sampleSize; | |||
mChannelsPerFrame = nChannels; | |||
mFramesPerPacket = 1; | |||
if (interleaved) | |||
mBytesPerPacket = mBytesPerFrame = nChannels * sampleSize; | |||
else { | |||
mBytesPerPacket = mBytesPerFrame = sampleSize; | |||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved; | |||
} | |||
} | |||
bool IsCanonical() const | |||
{ | |||
if (mFormatID != kAudioFormatLinearPCM) return false; | |||
UInt32 reqFormatFlags; | |||
UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagsSampleFractionMask); | |||
bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; | |||
unsigned sampleSize = SizeOf32(AudioSampleType); | |||
reqFormatFlags = kAudioFormatFlagsCanonical; | |||
UInt32 reqFrameSize = interleaved ? (mChannelsPerFrame * sampleSize) : sampleSize; | |||
return ((mFormatFlags & flagsMask) == reqFormatFlags | |||
&& mBitsPerChannel == 8 * sampleSize | |||
&& mFramesPerPacket == 1 | |||
&& mBytesPerFrame == reqFrameSize | |||
&& mBytesPerPacket == reqFrameSize); | |||
} | |||
void SetAUCanonical(UInt32 nChannels, bool interleaved) | |||
{ | |||
mFormatID = kAudioFormatLinearPCM; | |||
#if CA_PREFER_FIXED_POINT | |||
mFormatFlags = kAudioFormatFlagsCanonical | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift); | |||
#else | |||
mFormatFlags = kAudioFormatFlagsCanonical; | |||
#endif | |||
mChannelsPerFrame = nChannels; | |||
mFramesPerPacket = 1; | |||
mBitsPerChannel = 8 * SizeOf32(AudioUnitSampleType); | |||
if (interleaved) | |||
mBytesPerPacket = mBytesPerFrame = nChannels * SizeOf32(AudioUnitSampleType); | |||
else { | |||
mBytesPerPacket = mBytesPerFrame = SizeOf32(AudioUnitSampleType); | |||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved; | |||
} | |||
} | |||
void ChangeNumberChannels(UInt32 nChannels, bool interleaved) | |||
// alter an existing format | |||
{ | |||
Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats"); | |||
UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING | |||
if (wordSize == 0) | |||
wordSize = (mBitsPerChannel + 7) / 8; | |||
mChannelsPerFrame = nChannels; | |||
mFramesPerPacket = 1; | |||
if (interleaved) { | |||
mBytesPerPacket = mBytesPerFrame = nChannels * wordSize; | |||
mFormatFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonInterleaved); | |||
} else { | |||
mBytesPerPacket = mBytesPerFrame = wordSize; | |||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved; | |||
} | |||
} | |||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |||
// | |||
// other | |||
bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards=true) const; | |||
static bool FlagIndependentEquivalence(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y); | |||
static bool IsFunctionallyEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y); | |||
void Print() const { | |||
Print (stdout); | |||
} | |||
void Print(FILE* file) const { | |||
PrintFormat (file, "", "AudioStreamBasicDescription:"); | |||
} | |||
void PrintFormat(FILE *f, const char *indent, const char *name) const { | |||
char buf[256]; | |||
fprintf(f, "%s%s %s\n", indent, name, AsString(buf, sizeof(buf))); | |||
} | |||
void PrintFormat2(FILE *f, const char *indent, const char *name) const { // no trailing newline | |||
char buf[256]; | |||
fprintf(f, "%s%s %s", indent, name, AsString(buf, sizeof(buf))); | |||
} | |||
char * AsString(char *buf, size_t bufsize, bool brief=false) const; | |||
static void Print (const AudioStreamBasicDescription &inDesc) | |||
{ | |||
CAStreamBasicDescription desc(inDesc); | |||
desc.Print (); | |||
} | |||
OSStatus Save(CFPropertyListRef *outData) const; | |||
OSStatus Restore(CFPropertyListRef &inData); | |||
// Operations | |||
static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); } | |||
static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription); | |||
static void NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription); | |||
static void ResetFormat(AudioStreamBasicDescription& ioDescription); | |||
static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription); | |||
static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate = false); | |||
static void ModifyFormatFlagsForMatching(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y, UInt32& xFlags, UInt32& yFlags, bool converterOnly); | |||
#if CoreAudio_Debug | |||
static void PrintToLog(const AudioStreamBasicDescription& inDesc); | |||
#endif | |||
}; | |||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); | |||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); | |||
#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600)) | |||
inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); } | |||
inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); } | |||
inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); } | |||
inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); } | |||
#endif | |||
bool SanityCheck(const AudioStreamBasicDescription& x); | |||
#endif // __CAStreamBasicDescription_h__ |
@@ -1,233 +0,0 @@ | |||
/* | |||
File: CAThreadSafeList.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 __CAThreadSafeList_h__ | |||
#define __CAThreadSafeList_h__ | |||
#include "CAAtomicStack.h" | |||
// linked list of T's | |||
// T must define operator == | |||
template <class T> | |||
class TThreadSafeList { | |||
private: | |||
enum EEventType { kAdd, kRemove, kClear }; | |||
class Node { | |||
public: | |||
Node * mNext; | |||
EEventType mEventType; | |||
T mObject; | |||
Node *& next() { return mNext; } | |||
}; | |||
public: | |||
class iterator { | |||
public: | |||
iterator() { } | |||
iterator(Node *n) : mNode(n) { } | |||
bool operator == (const iterator &other) const { return this->mNode == other.mNode; } | |||
bool operator != (const iterator &other) const { return this->mNode != other.mNode; } | |||
T & operator * () const { return mNode->mObject; } | |||
iterator & operator ++ () { mNode = mNode->next(); return *this; } // preincrement | |||
iterator operator ++ (int) { iterator tmp = *this; mNode = mNode->next(); return tmp; } // postincrement | |||
private: | |||
Node * mNode; | |||
}; | |||
TThreadSafeList() { } | |||
~TThreadSafeList() | |||
{ | |||
mActiveList.free_all(); | |||
mPendingList.free_all(); | |||
mFreeList.free_all(); | |||
} | |||
// These may be called on any thread | |||
void deferred_add(const T &obj) // can be called on any thread | |||
{ | |||
Node *node = AllocNode(); | |||
node->mEventType = kAdd; | |||
node->mObject = obj; | |||
mPendingList.push_atomic(node); | |||
//mPendingList.dump("pending after add"); | |||
} | |||
void deferred_remove(const T &obj) // can be called on any thread | |||
{ | |||
Node *node = AllocNode(); | |||
node->mEventType = kRemove; | |||
node->mObject = obj; | |||
mPendingList.push_atomic(node); | |||
//mPendingList.dump("pending after remove"); | |||
} | |||
void deferred_clear() // can be called on any thread | |||
{ | |||
Node *node = AllocNode(); | |||
node->mEventType = kClear; | |||
mPendingList.push_atomic(node); | |||
} | |||
// These must be called from only one thread | |||
void update() // must only be called from one thread | |||
{ | |||
NodeStack reversed; | |||
Node *event, *node, *next; | |||
bool workDone = false; | |||
// reverse the events so they are in order | |||
event = mPendingList.pop_all(); | |||
while (event != NULL) { | |||
next = event->mNext; | |||
reversed.push_NA(event); | |||
event = next; | |||
workDone = true; | |||
} | |||
if (workDone) { | |||
//reversed.dump("pending popped"); | |||
//mActiveList.dump("active before update"); | |||
// now process them | |||
while ((event = reversed.pop_NA()) != NULL) { | |||
switch (event->mEventType) { | |||
case kAdd: | |||
{ | |||
Node **pnode; | |||
bool needToInsert = true; | |||
for (pnode = mActiveList.phead(); *pnode != NULL; pnode = &node->mNext) { | |||
node = *pnode; | |||
if (node->mObject == event->mObject) { | |||
//printf("already active!!!\n"); | |||
FreeNode(event); | |||
needToInsert = false; | |||
break; | |||
} | |||
} | |||
if (needToInsert) { | |||
// link the new event in at the end of the active list | |||
*pnode = event; | |||
event->mNext = NULL; | |||
} | |||
} | |||
break; | |||
case kRemove: | |||
// find matching node in the active list, remove it | |||
for (Node **pnode = mActiveList.phead(); *pnode != NULL; ) { | |||
node = *pnode; | |||
if (node->mObject == event->mObject) { | |||
*pnode = node->mNext; // remove from linked list | |||
FreeNode(node); | |||
break; | |||
} | |||
pnode = &node->mNext; | |||
} | |||
// dispose the request node | |||
FreeNode(event); | |||
break; | |||
case kClear: | |||
for (node = mActiveList.head(); node != NULL; ) { | |||
next = node->mNext; | |||
FreeNode(node); | |||
node = next; | |||
} | |||
FreeNode(event); | |||
break; | |||
default: | |||
//printf("invalid node type %d!\n", event->mEventType); | |||
break; | |||
} | |||
} | |||
//mActiveList.dump("active after update"); | |||
} | |||
} | |||
iterator begin() const { | |||
//mActiveList.dump("active at begin"); | |||
return iterator(mActiveList.head()); | |||
} | |||
iterator end() const { return iterator(NULL); } | |||
private: | |||
Node * AllocNode() | |||
{ | |||
Node *node = mFreeList.pop_atomic(); | |||
if (node == NULL) | |||
node = (Node *)CA_malloc(sizeof(Node)); | |||
return node; | |||
} | |||
void FreeNode(Node *node) | |||
{ | |||
mFreeList.push_atomic(node); | |||
} | |||
private: | |||
class NodeStack : public TAtomicStack<Node> { | |||
public: | |||
void free_all() { | |||
Node *node; | |||
while ((node = this->pop_NA()) != NULL) | |||
free(node); | |||
} | |||
Node ** phead() { return &this->mHead; } | |||
Node * head() const { return this->mHead; } | |||
}; | |||
NodeStack mActiveList; // what's actually in the container - only accessed on one thread | |||
NodeStack mPendingList; // add or remove requests - threadsafe | |||
NodeStack mFreeList; // free nodes for reuse - threadsafe | |||
}; | |||
#endif // __CAThreadSafeList_h__ |
@@ -1,194 +0,0 @@ | |||
/* | |||
File: CAVectorUnit.cpp | |||
Abstract: CAVectorUnit.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 "CAVectorUnit.h" | |||
#if !TARGET_OS_WIN32 | |||
#include <sys/sysctl.h> | |||
#elif HAS_IPP | |||
#include "ippdefs.h" | |||
#include "ippcore.h" | |||
#endif | |||
int gCAVectorUnitType = kVecUninitialized; | |||
#if TARGET_OS_WIN32 | |||
// Use cpuid to check if SSE2 is available. | |||
// Before calling this function make sure cpuid is available | |||
static SInt32 IsSSE2Available() | |||
{ | |||
int return_value; | |||
{ | |||
int r_edx; | |||
_asm | |||
{ | |||
mov eax, 0x01 | |||
cpuid | |||
mov r_edx, edx | |||
} | |||
return_value = (r_edx >> 26) & 0x1; | |||
} | |||
return return_value; | |||
} | |||
// Use cpuid to check if SSE3 is available. | |||
// Before calling this function make sure cpuid is available | |||
static SInt32 IsSSE3Available() | |||
{ | |||
SInt32 return_value; | |||
{ | |||
SInt32 r_ecx; | |||
_asm | |||
{ | |||
mov eax, 0x01 | |||
cpuid | |||
mov r_ecx, ecx | |||
} | |||
return_value = r_ecx & 0x1; | |||
} | |||
return return_value; | |||
} | |||
// Return true if the cpuid instruction is available. | |||
// The cpuid instruction is available if bit 21 in the EFLAGS register can be changed | |||
// This function may not work on Intel CPUs prior to Pentium (didn't test) | |||
static bool IsCpuidAvailable() | |||
{ | |||
SInt32 return_value = 0x0; | |||
_asm{ | |||
pushfd ; //push original EFLAGS | |||
pop eax ; //get original EFLAGS | |||
mov ecx, eax ; //save original EFLAGS | |||
xor eax, 200000h ; //flip ID bit in EFLAGS | |||
push eax ; //save new EFLAGS value on stack | |||
popfd ; //replace current EFLAGS value | |||
pushfd ; //get new EFLAGS | |||
pop eax ; //store new EFLAGS in EAX | |||
xor eax, ecx ; | |||
je end_cpuid_identify ; //can't toggle ID bit | |||
mov return_value, 0x1; | |||
end_cpuid_identify: | |||
nop; | |||
} | |||
return return_value; | |||
} | |||
#endif | |||
SInt32 CAVectorUnit_Examine() | |||
{ | |||
int result = kVecNone; | |||
#if TARGET_OS_WIN32 | |||
#if HAS_IPP | |||
// Initialize the static IPP library! This needs to be done before | |||
// any IPP function calls, otherwise we may have a performance penalty | |||
int status = ippStaticInit(); | |||
if ( status == ippStsNonIntelCpu ) | |||
{ | |||
IppCpuType cpuType = ippGetCpuType(); | |||
if ( cpuType >= ippCpuSSE || cpuType <= ippCpuSSE42 ) | |||
ippStaticInitCpu( cpuType ); | |||
} | |||
#endif | |||
{ | |||
// On Windows we use cpuid to detect the vector unit because it works on Intel and AMD. | |||
// The IPP library does not detect SSE on AMD processors. | |||
if (IsCpuidAvailable()) | |||
{ | |||
if(IsSSE3Available()) | |||
{ | |||
result = kVecSSE3; | |||
} | |||
else if(IsSSE2Available()) | |||
{ | |||
result = kVecSSE2; | |||
} | |||
} | |||
} | |||
#elif TARGET_OS_MAC | |||
#if DEBUG | |||
if (getenv("CA_NoVector")) { | |||
fprintf(stderr, "CA_NoVector set; Vector unit optimized routines will be bypassed\n"); | |||
return result; | |||
} | |||
else | |||
#endif | |||
{ | |||
#if (TARGET_CPU_PPC || TARGET_CPU_PPC64) | |||
int sels[2] = { CTL_HW, HW_VECTORUNIT }; | |||
int vType = 0; //0 == scalar only | |||
size_t length = sizeof(vType); | |||
int error = sysctl(sels, 2, &vType, &length, NULL, 0); | |||
if (!error && vType > 0) | |||
result = kVecAltivec; | |||
#elif (TARGET_CPU_X86 || TARGET_CPU_X86_64) | |||
static const struct { const char* kName; const int kVectype; } kStringVectypes[] = { | |||
{ "hw.optional.avx1_0", kVecAVX1 }, { "hw.optional.sse3", kVecSSE3 }, { "hw.optional.sse2", kVecSSE2 } | |||
}; | |||
static const size_t kNumStringVectypes = sizeof(kStringVectypes)/sizeof(kStringVectypes[0]); | |||
int i = 0, answer = 0; | |||
while(i != kNumStringVectypes) | |||
{ | |||
size_t length = sizeof(answer); | |||
int error = sysctlbyname(kStringVectypes[i].kName, &answer, &length, NULL, 0); | |||
if (!error && answer) | |||
{ | |||
result = kStringVectypes[i].kVectype; | |||
break; | |||
} | |||
++i; | |||
}; | |||
#elif CA_ARM_NEON | |||
result = kVecNeon; | |||
#endif | |||
} | |||
#endif | |||
gCAVectorUnitType = result; | |||
return result; | |||
} |
@@ -1,101 +0,0 @@ | |||
/* | |||
File: CAVectorUnit.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 __CAVectorUnit_h__ | |||
#define __CAVectorUnit_h__ | |||
#include <TargetConditionals.h> | |||
#include "CAVectorUnitTypes.h" | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreFoundation/CFBase.h> | |||
#else | |||
#include "CFBase.h" | |||
#endif | |||
// Unify checks for vector units. | |||
// Allow setting an environment variable "CA_NoVector" to turn off vectorized code at runtime (very useful for performance testing). | |||
extern int gCAVectorUnitType; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
extern SInt32 CAVectorUnit_Examine(); // expensive. use GetType() for lazy initialization and caching. | |||
static inline SInt32 CAVectorUnit_GetType() | |||
{ | |||
int x = gCAVectorUnitType; | |||
return (x != kVecUninitialized) ? x : CAVectorUnit_Examine(); | |||
} | |||
static inline Boolean CAVectorUnit_HasVectorUnit() | |||
{ | |||
return CAVectorUnit_GetType() > kVecNone; | |||
} | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#ifdef __cplusplus | |||
class CAVectorUnit { | |||
public: | |||
static SInt32 GetVectorUnitType() { return CAVectorUnit_GetType(); } | |||
static bool HasVectorUnit() { return GetVectorUnitType() > kVecNone; } | |||
static bool HasAltivec() { return GetVectorUnitType() == kVecAltivec; } | |||
static bool HasSSE2() { return GetVectorUnitType() >= kVecSSE2; } | |||
static bool HasSSE3() { return GetVectorUnitType() >= kVecSSE3; } | |||
static bool HasAVX1() { return GetVectorUnitType() >= kVecAVX1; } | |||
static bool HasNeon() { return GetVectorUnitType() == kVecNeon; } | |||
}; | |||
#endif | |||
#endif // __CAVectorUnit_h__ |
@@ -1,60 +0,0 @@ | |||
/* | |||
File: CAVectorUnitTypes.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 __CAVectorUnitTypes_h__ | |||
#define __CAVectorUnitTypes_h__ | |||
enum { | |||
kVecUninitialized = -1, | |||
kVecNone = 0, | |||
kVecAltivec = 1, | |||
kVecSSE2 = 100, | |||
kVecSSE3 = 101, | |||
kVecAVX1 = 110, | |||
kVecNeon = 200 | |||
}; | |||
#endif |
@@ -1,361 +0,0 @@ | |||
/* | |||
File: CAXException.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 __CAXException_h__ | |||
#define __CAXException_h__ | |||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
#include <CoreFoundation/CoreFoundation.h> | |||
#else | |||
#include <ConditionalMacros.h> | |||
#include <CoreFoundation.h> | |||
#endif | |||
#include "CADebugMacros.h" | |||
#include <ctype.h> | |||
//#include <stdio.h> | |||
#include <string.h> | |||
class CAX4CCString { | |||
public: | |||
CAX4CCString(OSStatus error) { | |||
// see if it appears to be a 4-char-code | |||
UInt32 beErr = CFSwapInt32HostToBig(error); | |||
char *str = mStr; | |||
memcpy(str + 1, &beErr, 4); | |||
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) { | |||
str[0] = str[5] = '\''; | |||
str[6] = '\0'; | |||
} else if (error > -200000 && error < 200000) | |||
// no, format it as an integer | |||
snprintf(str, sizeof(mStr), "%d", (int)error); | |||
else | |||
snprintf(str, sizeof(mStr), "0x%x", (int)error); | |||
} | |||
const char *get() const { return mStr; } | |||
operator const char *() const { return mStr; } | |||
private: | |||
char mStr[16]; | |||
}; | |||
class CAX4CCStringNoQuote { | |||
public: | |||
CAX4CCStringNoQuote(OSStatus error) { | |||
// see if it appears to be a 4-char-code | |||
UInt32 beErr = CFSwapInt32HostToBig(error); | |||
char *str = mStr; | |||
memcpy(str, &beErr, 4); | |||
if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) { | |||
str[4] = '\0'; | |||
} else if (error > -200000 && error < 200000) | |||
// no, format it as an integer | |||
snprintf(str, sizeof(mStr), "%d", (int)error); | |||
else | |||
snprintf(str, sizeof(mStr), "0x%x", (int)error); | |||
} | |||
const char *get() const { return mStr; } | |||
operator const char *() const { return mStr; } | |||
private: | |||
char mStr[16]; | |||
}; | |||
// An extended exception class that includes the name of the failed operation | |||
class CAXException { | |||
public: | |||
CAXException(const char *operation, OSStatus err) : | |||
mError(err) | |||
{ | |||
if (operation == NULL) | |||
mOperation[0] = '\0'; | |||
else if (strlen(operation) >= sizeof(mOperation)) { | |||
memcpy(mOperation, operation, sizeof(mOperation) - 1); | |||
mOperation[sizeof(mOperation) - 1] = '\0'; | |||
} else | |||
strlcpy(mOperation, operation, sizeof(mOperation)); | |||
} | |||
char *FormatError(char *str, size_t strsize) const | |||
{ | |||
return FormatError(str, strsize, mError); | |||
} | |||
char mOperation[256]; | |||
const OSStatus mError; | |||
// ------------------------------------------------- | |||
typedef void (*WarningHandler)(const char *msg, OSStatus err); | |||
static char *FormatError(char *str, size_t strsize, OSStatus error) | |||
{ | |||
strlcpy(str, CAX4CCString(error), strsize); | |||
return str; | |||
} | |||
static void Warning(const char *s, OSStatus error) | |||
{ | |||
if (sWarningHandler) | |||
(*sWarningHandler)(s, error); | |||
} | |||
static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; } | |||
private: | |||
static WarningHandler sWarningHandler; | |||
}; | |||
#if DEBUG || CoreAudio_Debug | |||
#define XThrowIfError(error, operation) \ | |||
do { \ | |||
OSStatus __err = error; \ | |||
if (__err) { \ | |||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\ | |||
__THROW_STOP; \ | |||
throw CAXException(operation, __err); \ | |||
} \ | |||
} while (0) | |||
#define XThrowIf(condition, error, operation) \ | |||
do { \ | |||
if (condition) { \ | |||
OSStatus __err = error; \ | |||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\ | |||
__THROW_STOP; \ | |||
throw CAXException(operation, __err); \ | |||
} \ | |||
} while (0) | |||
#define XRequireNoError(error, label) \ | |||
do { \ | |||
OSStatus __err = error; \ | |||
if (__err) { \ | |||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\ | |||
STOP; \ | |||
goto label; \ | |||
} \ | |||
} while (0) | |||
#define XAssert(assertion) \ | |||
do { \ | |||
if (!(assertion)) { \ | |||
DebugMessageN3("%s:%d: error: failed assertion: %s", __FILE__, __LINE__, #assertion); \ | |||
__ASSERT_STOP; \ | |||
} \ | |||
} while (0) | |||
#define XAssertNoError(error) \ | |||
do { \ | |||
OSStatus __err = error; \ | |||
if (__err) { \ | |||
DebugMessageN4("%s:%d: error %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\ | |||
STOP; \ | |||
} \ | |||
} while (0) | |||
#define ca_require_noerr(errorCode, exceptionLabel) \ | |||
do \ | |||
{ \ | |||
int evalOnceErrorCode = (errorCode); \ | |||
if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \ | |||
{ \ | |||
DebugMessageN5("ca_require_noerr: [%s, %d] (goto %s;) %s:%d", \ | |||
#errorCode, evalOnceErrorCode, \ | |||
#exceptionLabel, \ | |||
__FILE__, \ | |||
__LINE__); \ | |||
goto exceptionLabel; \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_verify_noerr(errorCode) \ | |||
do \ | |||
{ \ | |||
int evalOnceErrorCode = (errorCode); \ | |||
if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \ | |||
{ \ | |||
DebugMessageN4("ca_verify_noerr: [%s, %d] %s:%d", \ | |||
#errorCode, evalOnceErrorCode, \ | |||
__FILE__, \ | |||
__LINE__); \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_debug_string(message) \ | |||
do \ | |||
{ \ | |||
DebugMessageN3("ca_debug_string: %s %s:%d", \ | |||
message, \ | |||
__FILE__, \ | |||
__LINE__); \ | |||
} while ( 0 ) | |||
#define ca_verify(assertion) \ | |||
do \ | |||
{ \ | |||
if ( __builtin_expect(!(assertion), 0) ) \ | |||
{ \ | |||
DebugMessageN3("ca_verify: %s %s:%d", \ | |||
#assertion, \ | |||
__FILE__, \ | |||
__LINE__); \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_require(assertion, exceptionLabel) \ | |||
do \ | |||
{ \ | |||
if ( __builtin_expect(!(assertion), 0) ) \ | |||
{ \ | |||
DebugMessageN4("ca_require: %s %s %s:%d", \ | |||
#assertion, \ | |||
#exceptionLabel, \ | |||
__FILE__, \ | |||
__LINE__); \ | |||
goto exceptionLabel; \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_check(assertion) \ | |||
do \ | |||
{ \ | |||
if ( __builtin_expect(!(assertion), 0) ) \ | |||
{ \ | |||
DebugMessageN3("ca_check: %s %s:%d", \ | |||
#assertion, \ | |||
__FILE__, \ | |||
__LINE__); \ | |||
} \ | |||
} while ( 0 ) | |||
#else | |||
#define XThrowIfError(error, operation) \ | |||
do { \ | |||
OSStatus __err = error; \ | |||
if (__err) { \ | |||
throw CAXException(operation, __err); \ | |||
} \ | |||
} while (0) | |||
#define XThrowIf(condition, error, operation) \ | |||
do { \ | |||
if (condition) { \ | |||
OSStatus __err = error; \ | |||
throw CAXException(operation, __err); \ | |||
} \ | |||
} while (0) | |||
#define XRequireNoError(error, label) \ | |||
do { \ | |||
OSStatus __err = error; \ | |||
if (__err) { \ | |||
goto label; \ | |||
} \ | |||
} while (0) | |||
#define XAssert(assertion) \ | |||
do { \ | |||
if (!(assertion)) { \ | |||
} \ | |||
} while (0) | |||
#define XAssertNoError(error) \ | |||
do { \ | |||
/*OSStatus __err =*/ error; \ | |||
} while (0) | |||
#define ca_require_noerr(errorCode, exceptionLabel) \ | |||
do \ | |||
{ \ | |||
if ( __builtin_expect(0 != (errorCode), 0) ) \ | |||
{ \ | |||
goto exceptionLabel; \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_verify_noerr(errorCode) \ | |||
do \ | |||
{ \ | |||
if ( 0 != (errorCode) ) \ | |||
{ \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_debug_string(message) | |||
#define ca_verify(assertion) \ | |||
do \ | |||
{ \ | |||
if ( !(assertion) ) \ | |||
{ \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_require(assertion, exceptionLabel) \ | |||
do \ | |||
{ \ | |||
if ( __builtin_expect(!(assertion), 0) ) \ | |||
{ \ | |||
goto exceptionLabel; \ | |||
} \ | |||
} while ( 0 ) | |||
#define ca_check(assertion) \ | |||
do \ | |||
{ \ | |||
if ( !(assertion) ) \ | |||
{ \ | |||
} \ | |||
} while ( 0 ) | |||
#endif | |||
#define XThrow(error, operation) XThrowIf(true, error, operation) | |||
#define XThrowIfErr(error) XThrowIfError(error, #error) | |||
#endif // __CAXException_h__ |
@@ -1,369 +0,0 @@ | |||
/* | |||
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 |
@@ -1,353 +0,0 @@ | |||
/* | |||
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__ |
@@ -1,354 +0,0 @@ | |||
/* | |||
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 |
@@ -1,126 +0,0 @@ | |||
/* | |||
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__ |
@@ -52,7 +52,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wshorten-64-to-32", | |||
#include <AudioToolbox/AudioUnitUtilities.h> | |||
#include <CoreMIDI/MIDIServices.h> | |||
#include <QuartzCore/QuartzCore.h> | |||
#include "CoreAudioUtilityClasses/MusicDeviceBase.h" | |||
#include "AudioUnitSDK/MusicDeviceBase.h" | |||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
@@ -73,6 +73,8 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
#endif | |||
#endif | |||
#include <set> | |||
//============================================================================== | |||
using namespace juce; | |||
@@ -101,7 +103,7 @@ struct AudioProcessorHolder | |||
//============================================================================== | |||
class JuceAU : public AudioProcessorHolder, | |||
public MusicDeviceBase, | |||
public ausdk::MusicDeviceBase, | |||
public AudioProcessorListener, | |||
public AudioProcessorParameter::Listener | |||
{ | |||
@@ -239,24 +241,6 @@ public: | |||
} | |||
} | |||
//============================================================================== | |||
static OSStatus ComponentEntryDispatch (ComponentParameters* params, JuceAU* effect) | |||
{ | |||
if (effect == nullptr) | |||
return paramErr; | |||
switch (params->what) | |||
{ | |||
case kMusicDeviceMIDIEventSelect: | |||
case kMusicDeviceSysExSelect: | |||
return AUMIDIBase::ComponentEntryDispatch (params, effect); | |||
default: | |||
break; | |||
} | |||
return MusicDeviceBase::ComponentEntryDispatch (params, effect); | |||
} | |||
//============================================================================== | |||
bool BusCountWritable (AudioUnitScope scope) override | |||
{ | |||
@@ -380,7 +364,7 @@ public: | |||
AudioUnitScope inScope, | |||
AudioUnitElement inElement, | |||
UInt32& outDataSize, | |||
Boolean& outWritable) override | |||
bool& outWritable) override | |||
{ | |||
if (inScope == kAudioUnitScope_Global) | |||
{ | |||
@@ -813,8 +797,10 @@ public: | |||
#endif | |||
} | |||
UInt32 GetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, | |||
AudioChannelLayout* outLayoutPtr, Boolean& outWritable) override | |||
UInt32 GetAudioChannelLayout (AudioUnitScope scope, | |||
AudioUnitElement element, | |||
AudioChannelLayout* outLayoutPtr, | |||
bool& outWritable) override | |||
{ | |||
outWritable = false; | |||
@@ -839,22 +825,17 @@ public: | |||
return sizeInBytes; | |||
} | |||
UInt32 GetChannelLayoutTags (AudioUnitScope scope, AudioUnitElement element, AudioChannelLayoutTag* outLayoutTags) override | |||
std::vector<AudioChannelLayoutTag> GetChannelLayoutTags (AudioUnitScope inScope, AudioUnitElement inElement) override | |||
{ | |||
const auto info = getElementInfo (scope, element); | |||
const auto info = getElementInfo (inScope, inElement); | |||
if (info.error != noErr) | |||
return 0; | |||
return {}; | |||
if (busIgnoresLayout (info.isInput, info.busNr)) | |||
return 0; | |||
const Array<AudioChannelLayoutTag>& layouts = getSupportedBusLayouts (info.isInput, info.busNr); | |||
if (outLayoutTags != nullptr) | |||
std::copy (layouts.begin(), layouts.end(), outLayoutTags); | |||
return {}; | |||
return (UInt32) layouts.size(); | |||
return getSupportedBusLayouts (info.isInput, info.busNr); | |||
} | |||
OSStatus SetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout) override | |||
@@ -870,34 +851,29 @@ public: | |||
if (inLayout == nullptr) | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
if (const AUIOElement* ioElement = GetIOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element)) | |||
{ | |||
const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout); | |||
const int currentNumChannels = static_cast<int> (ioElement->GetStreamFormat().NumberChannels()); | |||
const int newChannelNum = newChannelSet.size(); | |||
auto& ioElement = IOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element); | |||
if (currentNumChannels != newChannelNum) | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout); | |||
const int currentNumChannels = static_cast<int> (ioElement.NumberChannels()); | |||
const int newChannelNum = newChannelSet.size(); | |||
// check if the new layout could be potentially set | |||
#ifdef JucePlugin_PreferredChannelConfigurations | |||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; | |||
if (currentNumChannels != newChannelNum) | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs)) | |||
return kAudioUnitErr_FormatNotSupported; | |||
#else | |||
if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet)) | |||
return kAudioUnitErr_FormatNotSupported; | |||
#endif | |||
// check if the new layout could be potentially set | |||
#ifdef JucePlugin_PreferredChannelConfigurations | |||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; | |||
getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet); | |||
if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs)) | |||
return kAudioUnitErr_FormatNotSupported; | |||
#else | |||
if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet)) | |||
return kAudioUnitErr_FormatNotSupported; | |||
#endif | |||
return noErr; | |||
} | |||
else | |||
jassertfalse; | |||
getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet); | |||
return kAudioUnitErr_InvalidElement; | |||
return noErr; | |||
} | |||
//============================================================================== | |||
@@ -1063,14 +1039,13 @@ public: | |||
bool CanScheduleParameters() const override { return false; } | |||
//============================================================================== | |||
ComponentResult Version() override { return JucePlugin_VersionCode; } | |||
bool SupportsTail() override { return true; } | |||
Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); } | |||
double getSampleRate() | |||
{ | |||
if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0) | |||
return GetOutput (0)->GetStreamFormat().mSampleRate; | |||
return Output (0).GetStreamFormat().mSampleRate; | |||
return 44100.0; | |||
} | |||
@@ -1236,14 +1211,16 @@ public: | |||
return ((! IsInitialized()) && (info.error == noErr)); | |||
} | |||
bool ValidFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& format) override | |||
bool ValidFormat (AudioUnitScope inScope, | |||
AudioUnitElement inElement, | |||
const AudioStreamBasicDescription& inNewFormat) override | |||
{ | |||
// DSP Quattro incorrectly uses global scope for the ValidFormat call | |||
if (scope == kAudioUnitScope_Global) | |||
return ValidFormat (kAudioUnitScope_Input, element, format) | |||
|| ValidFormat (kAudioUnitScope_Output, element, format); | |||
if (inScope == kAudioUnitScope_Global) | |||
return ValidFormat (kAudioUnitScope_Input, inElement, inNewFormat) | |||
|| ValidFormat (kAudioUnitScope_Output, inElement, inNewFormat); | |||
const auto info = getElementInfo (scope, element); | |||
const auto info = getElementInfo (inScope, inElement); | |||
if (info.error != noErr) | |||
return false; | |||
@@ -1251,15 +1228,15 @@ public: | |||
if (info.kind == BusKind::wrapperOnly) | |||
return true; | |||
const int newNumChannels = static_cast<int> (format.NumberChannels()); | |||
const int oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); | |||
const auto newNumChannels = static_cast<int> (inNewFormat.mChannelsPerFrame); | |||
const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); | |||
if (newNumChannels == oldNumChannels) | |||
return true; | |||
if (AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr)) | |||
{ | |||
if (! MusicDeviceBase::ValidFormat (scope, element, format)) | |||
if (! MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat)) | |||
return false; | |||
#ifdef JucePlugin_PreferredChannelConfigurations | |||
@@ -1276,17 +1253,20 @@ public: | |||
} | |||
// AU requires us to override this for the sole reason that we need to find a default layout tag if the number of channels have changed | |||
OSStatus ChangeStreamFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& old, const CAStreamBasicDescription& format) override | |||
OSStatus ChangeStreamFormat (AudioUnitScope inScope, | |||
AudioUnitElement inElement, | |||
const AudioStreamBasicDescription& inPrevFormat, | |||
const AudioStreamBasicDescription& inNewFormat) override | |||
{ | |||
const auto info = getElementInfo (scope, element); | |||
const auto info = getElementInfo (inScope, inElement); | |||
if (info.error != noErr) | |||
return info.error; | |||
AudioChannelLayoutTag& currentTag = getCurrentLayout (info.isInput, info.busNr); | |||
const int newNumChannels = static_cast<int> (format.NumberChannels()); | |||
const int oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); | |||
const auto newNumChannels = static_cast<int> (inNewFormat.mChannelsPerFrame); | |||
const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); | |||
#ifdef JucePlugin_PreferredChannelConfigurations | |||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; | |||
@@ -1310,7 +1290,7 @@ public: | |||
if (set == AudioChannelSet()) | |||
return kAudioUnitErr_FormatNotSupported; | |||
const auto err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format); | |||
const auto err = MusicDeviceBase::ChangeStreamFormat (inScope, inElement, inPrevFormat, inNewFormat); | |||
if (err == noErr) | |||
currentTag = CoreAudioLayouts::toCoreAudio (set); | |||
@@ -1375,7 +1355,7 @@ public: | |||
for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) | |||
{ | |||
if (pulledSucceeded[busIdx]) | |||
audioBuffer.set (busIdx, GetInput ((UInt32) busIdx)->GetBufferList(), mapper.get (true, busIdx)); | |||
audioBuffer.set (busIdx, Input ((UInt32) busIdx).GetBufferList(), mapper.get (true, busIdx)); | |||
else | |||
audioBuffer.clearInputBus (busIdx, (int) nFrames); | |||
} | |||
@@ -1396,7 +1376,7 @@ public: | |||
// copy back | |||
{ | |||
for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) | |||
audioBuffer.get (busIdx, GetOutput ((UInt32) busIdx)->GetBufferList(), mapper.get (false, busIdx)); | |||
audioBuffer.get (busIdx, Output ((UInt32) busIdx).GetBufferList(), mapper.get (false, busIdx)); | |||
} | |||
// process midi output | |||
@@ -1415,10 +1395,10 @@ public: | |||
ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; } | |||
//============================================================================== | |||
OSStatus HandleMidiEvent (UInt8 nStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override | |||
OSStatus HandleMIDIEvent (UInt8 inStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override | |||
{ | |||
#if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect | |||
const juce::uint8 data[] = { (juce::uint8) (nStatus | inChannel), | |||
const juce::uint8 data[] = { (juce::uint8) (inStatus | inChannel), | |||
(juce::uint8) inData1, | |||
(juce::uint8) inData2 }; | |||
@@ -1426,7 +1406,7 @@ public: | |||
incomingEvents.addEvent (data, 3, (int) inStartFrame); | |||
return noErr; | |||
#else | |||
ignoreUnused (nStatus, inChannel, inData1); | |||
ignoreUnused (inStatus, inChannel, inData1); | |||
ignoreUnused (inData2, inStartFrame); | |||
return kAudioUnitErr_PropertyNotInUse; | |||
#endif | |||
@@ -1877,7 +1857,7 @@ private: | |||
//============================================================================== | |||
Array<AUChannelInfo> channelInfo; | |||
Array<Array<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts; | |||
Array<std::vector<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts; | |||
Array<AudioChannelLayoutTag> currentInputLayout, currentOutputLayout; | |||
//============================================================================== | |||
@@ -1923,15 +1903,14 @@ private: | |||
for (unsigned int i = 0; i < numInputBuses; ++i) | |||
{ | |||
if (AUInputElement* input = GetInput (i)) | |||
{ | |||
const bool succeeded = (input->PullInput (flags, timestamp, i, nFrames) == noErr); | |||
auto& input = Input (i); | |||
if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded) | |||
AudioUnitHelpers::clearAudioBuffer (input->GetBufferList()); | |||
const bool succeeded = (input.PullInput (flags, timestamp, i, nFrames) == noErr); | |||
pulledSucceeded[i] = succeeded; | |||
} | |||
if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded) | |||
AudioUnitHelpers::clearAudioBuffer (input.GetBufferList()); | |||
pulledSucceeded[i] = succeeded; | |||
} | |||
} | |||
@@ -1942,13 +1921,13 @@ private: | |||
for (UInt32 busIdx = 0; busIdx < numWrapperBuses; ++busIdx) | |||
{ | |||
AUOutputElement* output = GetOutput (busIdx); | |||
auto& output = Output (busIdx); | |||
if (output->WillAllocateBuffer()) | |||
output->PrepareBuffer (nFrames); | |||
if (output.WillAllocateBuffer()) | |||
output.PrepareBuffer (nFrames); | |||
if (busIdx >= (UInt32) numProcessorBuses) | |||
AudioUnitHelpers::clearAudioBuffer (output->GetBufferList()); | |||
AudioUnitHelpers::clearAudioBuffer (output.GetBufferList()); | |||
} | |||
} | |||
@@ -2026,7 +2005,7 @@ private: | |||
void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels) | |||
{ | |||
AUIOElement* element = GetElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast<UInt32> (busIdx))->AsIOElement(); | |||
auto* element = Element (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast<UInt32> (busIdx)).AsIOElement(); | |||
jassert (element != nullptr); | |||
bufferList = &element->GetBufferList(); | |||
@@ -2124,7 +2103,7 @@ private: | |||
if (forceUseLegacyParamIDs) | |||
{ | |||
Globals()->UseIndexedParameters (numParams); | |||
Globals()->UseIndexedParameters (static_cast<UInt32> (numParams)); | |||
} | |||
else | |||
{ | |||
@@ -2261,8 +2240,8 @@ private: | |||
const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); | |||
const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); | |||
const int numInputElements = static_cast<int> (GetScope(kAudioUnitScope_Input). GetNumberOfElements()); | |||
const int numOutputElements = static_cast<int> (GetScope(kAudioUnitScope_Output).GetNumberOfElements()); | |||
const int numInputElements = static_cast<int> (GetScope (kAudioUnitScope_Input). GetNumberOfElements()); | |||
const int numOutputElements = static_cast<int> (GetScope (kAudioUnitScope_Output).GetNumberOfElements()); | |||
AudioProcessor::BusesLayout requestedLayouts; | |||
for (int dir = 0; dir < 2; ++dir) | |||
@@ -2274,8 +2253,8 @@ private: | |||
for (int busIdx = 0; busIdx < n; ++busIdx) | |||
{ | |||
const AUIOElement* element = (busIdx < numAUElements ? GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr); | |||
const int numChannels = (element != nullptr ? static_cast<int> (element->GetStreamFormat().NumberChannels()) : 0); | |||
const auto* element = (busIdx < numAUElements ? &IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr); | |||
const int numChannels = (element != nullptr ? static_cast<int> (element->NumberChannels()) : 0); | |||
AudioChannelLayoutTag currentLayoutTag = isInput ? currentInputLayout[busIdx] : currentOutputLayout[busIdx]; | |||
const int tagNumChannels = currentLayoutTag & 0xffff; | |||
@@ -2314,20 +2293,12 @@ private: | |||
if (numChannels == 0) | |||
return noErr; | |||
if (AUIOElement* element = GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr)) | |||
{ | |||
element->SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName())); | |||
CAStreamBasicDescription streamDescription; | |||
streamDescription.mSampleRate = getSampleRate(); | |||
auto& element = IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr); | |||
streamDescription.SetCanonical ((UInt32) numChannels, false); | |||
return element->SetStreamFormat (streamDescription); | |||
} | |||
else | |||
jassertfalse; | |||
element.SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName())); | |||
return kAudioUnitErr_InvalidElement; | |||
const auto streamDescription = ausdk::ASBD::CreateCommonFloat32 (getSampleRate(), (UInt32) numChannels); | |||
return element.SetStreamFormat (streamDescription); | |||
} | |||
//============================================================================== | |||
@@ -2355,14 +2326,16 @@ private: | |||
} | |||
//============================================================================== | |||
Array<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } | |||
const Array<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } | |||
std::vector<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } | |||
const std::vector<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } | |||
AudioChannelLayoutTag& getCurrentLayout (bool isInput, int bus) noexcept { return (isInput ? currentInputLayout : currentOutputLayout).getReference (bus); } | |||
AudioChannelLayoutTag getCurrentLayout (bool isInput, int bus) const noexcept { return (isInput ? currentInputLayout : currentOutputLayout)[bus]; } | |||
//============================================================================== | |||
void addSupportedLayoutTagsForBus (bool isInput, int busNum, Array<AudioChannelLayoutTag>& tags) | |||
std::vector<AudioChannelLayoutTag> getSupportedLayoutTagsForBus (bool isInput, int busNum) const | |||
{ | |||
std::set<AudioChannelLayoutTag> tags; | |||
if (AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNum)) | |||
{ | |||
#ifndef JucePlugin_PreferredChannelConfigurations | |||
@@ -2370,7 +2343,7 @@ private: | |||
for (auto tag : knownTags) | |||
if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag))) | |||
tags.addIfNotAlreadyThere (tag); | |||
tags.insert (tag); | |||
#endif | |||
// add discrete layout tags | |||
@@ -2384,10 +2357,12 @@ private: | |||
tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); | |||
#else | |||
if (bus->isLayoutSupported (AudioChannelSet::discreteChannels (ch))) | |||
tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); | |||
tags.insert (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); | |||
#endif | |||
} | |||
} | |||
return std::vector<AudioChannelLayoutTag> (tags.begin(), tags.end()); | |||
} | |||
void addSupportedLayoutTagsForDirection (bool isInput) | |||
@@ -2397,12 +2372,7 @@ private: | |||
auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput); | |||
for (int busNr = 0; busNr < numBuses; ++busNr) | |||
{ | |||
Array<AudioChannelLayoutTag> busLayouts; | |||
addSupportedLayoutTagsForBus (isInput, busNr, busLayouts); | |||
layouts.add (busLayouts); | |||
} | |||
layouts.add (getSupportedLayoutTagsForBus (isInput, busNr)); | |||
} | |||
void addSupportedLayoutTags() | |||
@@ -2425,10 +2395,10 @@ private: | |||
void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement) | |||
{ | |||
if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName | |||
&& juceFilter != nullptr && mContextName != nullptr) | |||
&& juceFilter != nullptr && GetContextName() != nullptr) | |||
{ | |||
AudioProcessor::TrackProperties props; | |||
props.name = String::fromCFString (mContextName); | |||
props.name = String::fromCFString (GetContextName()); | |||
juceFilter->updateTrackProperties (props); | |||
} | |||
@@ -2444,48 +2414,17 @@ private: | |||
}; | |||
//============================================================================== | |||
#define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \ | |||
extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \ | |||
extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \ | |||
{ \ | |||
PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnit; \ | |||
return ComponentEntryPoint<Class>::Dispatch (params, obj); \ | |||
} | |||
#if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect | |||
#define FACTORY_BASE_CLASS AUMIDIEffectFactory | |||
#define FACTORY_BASE_CLASS ausdk::AUMusicDeviceFactory | |||
#else | |||
#define FACTORY_BASE_CLASS AUBaseFactory | |||
#endif | |||
#define JUCE_FACTORY_ENTRYX(Class, Name) \ | |||
extern "C" __attribute__((visibility("default"))) void* Name ## Factory (const AudioComponentDescription* desc); \ | |||
extern "C" __attribute__((visibility("default"))) void* Name ## Factory (const AudioComponentDescription* desc) \ | |||
{ \ | |||
PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnit; \ | |||
return FACTORY_BASE_CLASS<Class>::Factory (desc); \ | |||
} | |||
#define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) | |||
#define JUCE_FACTORY_ENTRY(Class, Name) JUCE_FACTORY_ENTRYX(Class, Name) | |||
//============================================================================== | |||
JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry) | |||
#ifndef AUDIOCOMPONENT_ENTRY | |||
#define JUCE_DISABLE_AU_FACTORY_ENTRY 1 | |||
#endif | |||
#if ! JUCE_DISABLE_AU_FACTORY_ENTRY // (You might need to disable this for old Xcode 3 builds) | |||
JUCE_FACTORY_ENTRY (JuceAU, JucePlugin_AUExportPrefix) | |||
#define FACTORY_BASE_CLASS ausdk::AUBaseFactory | |||
#endif | |||
#if ! JUCE_DISABLE_AU_FACTORY_ENTRY | |||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", "-Wzero-as-null-pointer-constant") | |||
AUSDK_COMPONENT_ENTRY (FACTORY_BASE_CLASS, JuceAU) | |||
#include "CoreAudioUtilityClasses/AUPlugInDispatch.cpp" | |||
#define JUCE_AU_ENTRY_POINT_NAME JUCE_CONCAT (JucePlugin_AUExportPrefix, Factory) | |||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
#endif | |||
extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc); | |||
AUSDK_EXPORT extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc) { return JuceAUFactory (inDesc); } | |||
#endif |
@@ -1,150 +0,0 @@ | |||
/* | |||
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 | |||
// JUCE CHANGE STARTS HERE | |||
#if defined(arm64_YES) | |||
#if defined(NeedLeadingComma) | |||
, | |||
#endif | |||
cmpThreadSafeOnMac, | |||
'dlle', RES_ID, 9 | |||
#define NeedLeadingComma 1 | |||
#endif | |||
// JUCE CHANGE ENDS HERE | |||
} | |||
}; | |||
#undef RES_ID | |||
#undef COMP_TYPE | |||
#undef COMP_SUBTYPE | |||
#undef COMP_MANUF | |||
#undef VERSION | |||
#undef NAME | |||
#undef DESCRIPTION | |||
#undef ENTRY_POINT | |||
#undef NeedLeadingComma |
@@ -1,50 +0,0 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2022 - Raw Material Software Limited | |||
JUCE is an open source library subject to commercial or open-source | |||
licensing. | |||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License | |||
Agreement and JUCE Privacy Policy. | |||
End User License Agreement: www.juce.com/juce-7-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#define UseExtendedThingResource 1 | |||
#include <AudioUnit.r> | |||
//============================================================================== | |||
/* The JucePluginDefines file should be a file in your project, containing info to describe the | |||
plugin's name, type, etc. The Projucer will generate this file automatically for you. | |||
You may need to adjust the include path of your project to make sure it can be | |||
found by this include statement. (Don't hack this file to change the include path) | |||
*/ | |||
#include "JucePluginDefines.h" | |||
//============================================================================== | |||
// component resources for Audio Unit | |||
#define RES_ID 1000 | |||
#define COMP_TYPE JucePlugin_AUMainType | |||
#define COMP_SUBTYPE JucePlugin_AUSubType | |||
#define COMP_MANUF JucePlugin_AUManufacturerCode | |||
#define VERSION JucePlugin_VersionCode | |||
#define NAME JucePlugin_Manufacturer ": " JucePlugin_Name | |||
#define DESCRIPTION JucePlugin_Desc | |||
#define ENTRY_POINT JucePlugin_AUExportPrefixQuoted "Entry" | |||
#include "AUResources.r" |
@@ -60,21 +60,42 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wparentheses", | |||
#define verify_noerr(errorCode) __Verify_noErr(errorCode) | |||
#endif | |||
#include "AU/CoreAudioUtilityClasses/AUBase.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUBuffer.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUDispatch.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUInputElement.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUMIDIBase.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUOutputBase.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUOutputElement.cpp" | |||
#include "AU/CoreAudioUtilityClasses/AUScopeElement.cpp" | |||
#include "AU/CoreAudioUtilityClasses/CAAUParameter.cpp" | |||
#include "AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp" | |||
#include "AU/CoreAudioUtilityClasses/CAMutex.cpp" | |||
#include "AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp" | |||
#include "AU/CoreAudioUtilityClasses/CAVectorUnit.cpp" | |||
#include "AU/CoreAudioUtilityClasses/ComponentBase.cpp" | |||
#include "AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp" | |||
#if ! defined (MAC_OS_VERSION_11_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0 | |||
// These constants are only defined in the macOS 11+ SDKs | |||
enum MIDICVStatus : unsigned int | |||
{ | |||
kMIDICVStatusNoteOff = 0x8, | |||
kMIDICVStatusNoteOn = 0x9, | |||
kMIDICVStatusPolyPressure = 0xA, | |||
kMIDICVStatusControlChange = 0xB, | |||
kMIDICVStatusProgramChange = 0xC, | |||
kMIDICVStatusChannelPressure = 0xD, | |||
kMIDICVStatusPitchBend = 0xE, | |||
kMIDICVStatusRegisteredPNC = 0x0, | |||
kMIDICVStatusAssignablePNC = 0x1, | |||
kMIDICVStatusRegisteredControl = 0x2, | |||
kMIDICVStatusAssignableControl = 0x3, | |||
kMIDICVStatusRelRegisteredControl = 0x4, | |||
kMIDICVStatusRelAssignableControl = 0x5, | |||
kMIDICVStatusPerNotePitchBend = 0x6, | |||
kMIDICVStatusPerNoteMgmt = 0xF | |||
}; | |||
#endif | |||
#include "AU/AudioUnitSDK/AUBase.cpp" | |||
#include "AU/AudioUnitSDK/AUBuffer.cpp" | |||
#include "AU/AudioUnitSDK/AUBufferAllocator.cpp" | |||
#include "AU/AudioUnitSDK/AUEffectBase.cpp" | |||
#include "AU/AudioUnitSDK/AUInputElement.cpp" | |||
#include "AU/AudioUnitSDK/AUMIDIBase.cpp" | |||
#include "AU/AudioUnitSDK/AUMIDIEffectBase.cpp" | |||
#include "AU/AudioUnitSDK/AUOutputElement.cpp" | |||
#include "AU/AudioUnitSDK/AUPlugInDispatch.cpp" | |||
#include "AU/AudioUnitSDK/AUScopeElement.cpp" | |||
#include "AU/AudioUnitSDK/ComponentBase.cpp" | |||
#include "AU/AudioUnitSDK/MusicDeviceBase.cpp" | |||
#undef verify | |||
#undef verify_noerr | |||