@@ -4,6 +4,28 @@ JUCE breaking changes | |||||
develop | 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 | Change | ||||
------ | ------ | ||||
Previously, the AudioProcessorGraph would call processBlockBypassed on any | 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)) | - [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)) | - [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)) | - [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)) | - [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)) | - [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)) | - [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/flac \ | ||||
build/juce_audio_formats/codecs/oggvorbis \ | build/juce_audio_formats/codecs/oggvorbis \ | ||||
build/juce_audio_devices/native \ | 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_browser_plugin_client/juce_browser_plugin.h \ | ||||
build/juce_core/native \ | build/juce_core/native \ | ||||
build/juce_events/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) | _juce_link_frameworks("${target_name}" INTERFACE AudioUnit) | ||||
endif() | endif() | ||||
elseif(format STREQUAL "AU") | 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) | _juce_link_frameworks("${target_name}" INTERFACE AudioUnit CoreAudioKit) | ||||
endif() | endif() | ||||
endfunction() | 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")) | 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_CURL_LINUX_DEPS libcurl) | ||||
_juce_create_pkgconfig_target(JUCE_BROWSER_LINUX_DEPS webkit2gtk-4.0 gtk+-x11-3.0) | _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() | endif() | ||||
# We set up default/fallback copy dirs here. If you need different copy dirs, use | # 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 | # 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, | # JUCE_USE_CURL, JUCE_WEB_BROWSER, or JUCE_IN_APP_PURCHASES have been explicitly turned off, | ||||
# and then link libraries as appropriate. | # and then link libraries as appropriate. | ||||
@@ -1285,10 +1218,6 @@ function(_juce_configure_plugin_targets target) | |||||
_juce_configure_app_bundle(${target} ${target}_Standalone) | _juce_configure_app_bundle(${target} ${target}_Standalone) | ||||
endif() | endif() | ||||
if(TARGET ${target}_AU) | |||||
_juce_add_au_resource_fork(${target} ${target}_AU) | |||||
endif() | |||||
if(TARGET ${target}_AAX) | if(TARGET ${target}_AAX) | ||||
target_link_libraries(${target}_AAX PRIVATE juce_aax_sdk) | target_link_libraries(${target}_AAX PRIVATE juce_aax_sdk) | ||||
endif() | endif() | ||||
@@ -1048,7 +1048,7 @@ public: | |||||
struct XcodeTarget : build_tools::ProjectType::Target | struct XcodeTarget : build_tools::ProjectType::Target | ||||
{ | { | ||||
//============================================================================== | //============================================================================== | ||||
XcodeTarget (build_tools::ProjectType::Target::Type targetType, const XcodeProjectExporter& exporter) | |||||
XcodeTarget (Type targetType, const XcodeProjectExporter& exporter) | |||||
: Target (targetType), | : Target (targetType), | ||||
owner (exporter) | owner (exporter) | ||||
{ | { | ||||
@@ -1699,10 +1699,17 @@ public: | |||||
s.set ("CODE_SIGN_ENTITLEMENTS", getEntitlementsFilename().quoted()); | 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++" | s.set ("CLANG_CXX_LANGUAGE_STANDARD", (String (owner.shouldUseGNUExtensions() ? "gnu++" | ||||
: "c++") + cppStandard).quoted()); | : "c++") + cppStandard).quoted()); | ||||
@@ -1970,10 +1977,15 @@ public: | |||||
if (owner.project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client")) | 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); | 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 <AudioToolbox/AudioUnitUtilities.h> | ||||
#include <CoreMIDI/MIDIServices.h> | #include <CoreMIDI/MIDIServices.h> | ||||
#include <QuartzCore/QuartzCore.h> | #include <QuartzCore/QuartzCore.h> | ||||
#include "CoreAudioUtilityClasses/MusicDeviceBase.h" | |||||
#include "AudioUnitSDK/MusicDeviceBase.h" | |||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE | JUCE_END_IGNORE_WARNINGS_GCC_LIKE | ||||
@@ -73,6 +73,8 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||||
#endif | #endif | ||||
#endif | #endif | ||||
#include <set> | |||||
//============================================================================== | //============================================================================== | ||||
using namespace juce; | using namespace juce; | ||||
@@ -101,7 +103,7 @@ struct AudioProcessorHolder | |||||
//============================================================================== | //============================================================================== | ||||
class JuceAU : public AudioProcessorHolder, | class JuceAU : public AudioProcessorHolder, | ||||
public MusicDeviceBase, | |||||
public ausdk::MusicDeviceBase, | |||||
public AudioProcessorListener, | public AudioProcessorListener, | ||||
public AudioProcessorParameter::Listener | 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 | bool BusCountWritable (AudioUnitScope scope) override | ||||
{ | { | ||||
@@ -380,7 +364,7 @@ public: | |||||
AudioUnitScope inScope, | AudioUnitScope inScope, | ||||
AudioUnitElement inElement, | AudioUnitElement inElement, | ||||
UInt32& outDataSize, | UInt32& outDataSize, | ||||
Boolean& outWritable) override | |||||
bool& outWritable) override | |||||
{ | { | ||||
if (inScope == kAudioUnitScope_Global) | if (inScope == kAudioUnitScope_Global) | ||||
{ | { | ||||
@@ -813,8 +797,10 @@ public: | |||||
#endif | #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; | outWritable = false; | ||||
@@ -839,22 +825,17 @@ public: | |||||
return sizeInBytes; | 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) | if (info.error != noErr) | ||||
return 0; | |||||
return {}; | |||||
if (busIgnoresLayout (info.isInput, info.busNr)) | 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 | OSStatus SetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout) override | ||||
@@ -870,34 +851,29 @@ public: | |||||
if (inLayout == nullptr) | if (inLayout == nullptr) | ||||
return kAudioUnitErr_InvalidPropertyValue; | 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; } | bool CanScheduleParameters() const override { return false; } | ||||
//============================================================================== | //============================================================================== | ||||
ComponentResult Version() override { return JucePlugin_VersionCode; } | |||||
bool SupportsTail() override { return true; } | bool SupportsTail() override { return true; } | ||||
Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); } | Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); } | ||||
double getSampleRate() | double getSampleRate() | ||||
{ | { | ||||
if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0) | if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0) | ||||
return GetOutput (0)->GetStreamFormat().mSampleRate; | |||||
return Output (0).GetStreamFormat().mSampleRate; | |||||
return 44100.0; | return 44100.0; | ||||
} | } | ||||
@@ -1236,14 +1211,16 @@ public: | |||||
return ((! IsInitialized()) && (info.error == noErr)); | 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 | // 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) | if (info.error != noErr) | ||||
return false; | return false; | ||||
@@ -1251,15 +1228,15 @@ public: | |||||
if (info.kind == BusKind::wrapperOnly) | if (info.kind == BusKind::wrapperOnly) | ||||
return true; | 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) | if (newNumChannels == oldNumChannels) | ||||
return true; | return true; | ||||
if (AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr)) | if (AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr)) | ||||
{ | { | ||||
if (! MusicDeviceBase::ValidFormat (scope, element, format)) | |||||
if (! MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat)) | |||||
return false; | return false; | ||||
#ifdef JucePlugin_PreferredChannelConfigurations | #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 | // 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) | if (info.error != noErr) | ||||
return info.error; | return info.error; | ||||
AudioChannelLayoutTag& currentTag = getCurrentLayout (info.isInput, info.busNr); | 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 | #ifdef JucePlugin_PreferredChannelConfigurations | ||||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; | short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; | ||||
@@ -1310,7 +1290,7 @@ public: | |||||
if (set == AudioChannelSet()) | if (set == AudioChannelSet()) | ||||
return kAudioUnitErr_FormatNotSupported; | return kAudioUnitErr_FormatNotSupported; | ||||
const auto err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format); | |||||
const auto err = MusicDeviceBase::ChangeStreamFormat (inScope, inElement, inPrevFormat, inNewFormat); | |||||
if (err == noErr) | if (err == noErr) | ||||
currentTag = CoreAudioLayouts::toCoreAudio (set); | currentTag = CoreAudioLayouts::toCoreAudio (set); | ||||
@@ -1375,7 +1355,7 @@ public: | |||||
for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) | for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) | ||||
{ | { | ||||
if (pulledSucceeded[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 | else | ||||
audioBuffer.clearInputBus (busIdx, (int) nFrames); | audioBuffer.clearInputBus (busIdx, (int) nFrames); | ||||
} | } | ||||
@@ -1396,7 +1376,7 @@ public: | |||||
// copy back | // copy back | ||||
{ | { | ||||
for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) | 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 | // process midi output | ||||
@@ -1415,10 +1395,10 @@ public: | |||||
ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; } | 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 | #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) inData1, | ||||
(juce::uint8) inData2 }; | (juce::uint8) inData2 }; | ||||
@@ -1426,7 +1406,7 @@ public: | |||||
incomingEvents.addEvent (data, 3, (int) inStartFrame); | incomingEvents.addEvent (data, 3, (int) inStartFrame); | ||||
return noErr; | return noErr; | ||||
#else | #else | ||||
ignoreUnused (nStatus, inChannel, inData1); | |||||
ignoreUnused (inStatus, inChannel, inData1); | |||||
ignoreUnused (inData2, inStartFrame); | ignoreUnused (inData2, inStartFrame); | ||||
return kAudioUnitErr_PropertyNotInUse; | return kAudioUnitErr_PropertyNotInUse; | ||||
#endif | #endif | ||||
@@ -1877,7 +1857,7 @@ private: | |||||
//============================================================================== | //============================================================================== | ||||
Array<AUChannelInfo> channelInfo; | Array<AUChannelInfo> channelInfo; | ||||
Array<Array<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts; | |||||
Array<std::vector<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts; | |||||
Array<AudioChannelLayoutTag> currentInputLayout, currentOutputLayout; | Array<AudioChannelLayoutTag> currentInputLayout, currentOutputLayout; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -1923,15 +1903,14 @@ private: | |||||
for (unsigned int i = 0; i < numInputBuses; ++i) | 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) | 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) | 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) | 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); | jassert (element != nullptr); | ||||
bufferList = &element->GetBufferList(); | bufferList = &element->GetBufferList(); | ||||
@@ -2124,7 +2103,7 @@ private: | |||||
if (forceUseLegacyParamIDs) | if (forceUseLegacyParamIDs) | ||||
{ | { | ||||
Globals()->UseIndexedParameters (numParams); | |||||
Globals()->UseIndexedParameters (static_cast<UInt32> (numParams)); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -2261,8 +2240,8 @@ private: | |||||
const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); | const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); | ||||
const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); | 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; | AudioProcessor::BusesLayout requestedLayouts; | ||||
for (int dir = 0; dir < 2; ++dir) | for (int dir = 0; dir < 2; ++dir) | ||||
@@ -2274,8 +2253,8 @@ private: | |||||
for (int busIdx = 0; busIdx < n; ++busIdx) | 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]; | AudioChannelLayoutTag currentLayoutTag = isInput ? currentInputLayout[busIdx] : currentOutputLayout[busIdx]; | ||||
const int tagNumChannels = currentLayoutTag & 0xffff; | const int tagNumChannels = currentLayoutTag & 0xffff; | ||||
@@ -2314,20 +2293,12 @@ private: | |||||
if (numChannels == 0) | if (numChannels == 0) | ||||
return noErr; | 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) noexcept { return (isInput ? currentInputLayout : currentOutputLayout).getReference (bus); } | ||||
AudioChannelLayoutTag getCurrentLayout (bool isInput, int bus) const noexcept { return (isInput ? currentInputLayout : currentOutputLayout)[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)) | if (AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNum)) | ||||
{ | { | ||||
#ifndef JucePlugin_PreferredChannelConfigurations | #ifndef JucePlugin_PreferredChannelConfigurations | ||||
@@ -2370,7 +2343,7 @@ private: | |||||
for (auto tag : knownTags) | for (auto tag : knownTags) | ||||
if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag))) | if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag))) | ||||
tags.addIfNotAlreadyThere (tag); | |||||
tags.insert (tag); | |||||
#endif | #endif | ||||
// add discrete layout tags | // add discrete layout tags | ||||
@@ -2384,10 +2357,12 @@ private: | |||||
tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); | tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); | ||||
#else | #else | ||||
if (bus->isLayoutSupported (AudioChannelSet::discreteChannels (ch))) | 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 | #endif | ||||
} | } | ||||
} | } | ||||
return std::vector<AudioChannelLayoutTag> (tags.begin(), tags.end()); | |||||
} | } | ||||
void addSupportedLayoutTagsForDirection (bool isInput) | void addSupportedLayoutTagsForDirection (bool isInput) | ||||
@@ -2397,12 +2372,7 @@ private: | |||||
auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput); | auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput); | ||||
for (int busNr = 0; busNr < numBuses; ++busNr) | for (int busNr = 0; busNr < numBuses; ++busNr) | ||||
{ | |||||
Array<AudioChannelLayoutTag> busLayouts; | |||||
addSupportedLayoutTagsForBus (isInput, busNr, busLayouts); | |||||
layouts.add (busLayouts); | |||||
} | |||||
layouts.add (getSupportedLayoutTagsForBus (isInput, busNr)); | |||||
} | } | ||||
void addSupportedLayoutTags() | void addSupportedLayoutTags() | ||||
@@ -2425,10 +2395,10 @@ private: | |||||
void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement) | void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement) | ||||
{ | { | ||||
if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName | if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName | ||||
&& juceFilter != nullptr && mContextName != nullptr) | |||||
&& juceFilter != nullptr && GetContextName() != nullptr) | |||||
{ | { | ||||
AudioProcessor::TrackProperties props; | AudioProcessor::TrackProperties props; | ||||
props.name = String::fromCFString (mContextName); | |||||
props.name = String::fromCFString (GetContextName()); | |||||
juceFilter->updateTrackProperties (props); | 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 | #if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect | ||||
#define FACTORY_BASE_CLASS AUMIDIEffectFactory | |||||
#define FACTORY_BASE_CLASS ausdk::AUMusicDeviceFactory | |||||
#else | #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 | #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 | #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) | #define verify_noerr(errorCode) __Verify_noErr(errorCode) | ||||
#endif | #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 | ||||
#undef verify_noerr | #undef verify_noerr | ||||