mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
AU: Replace CoreAudioUtilityClasses with files from new SDK
This commit is contained in:
parent
c0f31aa12a
commit
f8e91d4003
87 changed files with 7700 additions and 15819 deletions
|
|
@ -4,6 +4,28 @@ JUCE breaking changes
|
|||
develop
|
||||
=======
|
||||
|
||||
Change
|
||||
------
|
||||
Resource forks are no longer generated for Audio Unit plug-ins.
|
||||
|
||||
Possible Issues
|
||||
---------------
|
||||
New builds of JUCE Audio Units may no longer load in old hosts that use the
|
||||
Component Manager to discover plug-ins.
|
||||
|
||||
Workaround
|
||||
----------
|
||||
No workaround is available.
|
||||
|
||||
Rationale
|
||||
---------
|
||||
The Component Manager is deprecated in macOS 10.8 and later, so the majority of
|
||||
hosts have now implemented support for the new plist-based discovery mechanism.
|
||||
The new AudioUnitSDK (https://github.com/apple/AudioUnitSDK) provided by Apple
|
||||
to replace the old Core Audio Utility Classes no longer includes the files
|
||||
required to generate resource forks.
|
||||
|
||||
|
||||
Change
|
||||
------
|
||||
Previously, the AudioProcessorGraph would call processBlockBypassed on any
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ The JUCE framework contains the following dependencies:
|
|||
- [Oboe](modules/juce_audio_devices/native/oboe/) ([Apache 2.0](modules/juce_audio_devices/native/oboe/LICENSE))
|
||||
- [FLAC](modules/juce_audio_formats/codecs/flac/) ([BSD](modules/juce_audio_formats/codecs/flac/Flac%20Licence.txt))
|
||||
- [Ogg Vorbis](modules/juce_audio_formats/codecs/oggvorbis/) ([BSD](modules/juce_audio_formats/codecs/oggvorbis/Ogg%20Vorbis%20Licence.txt))
|
||||
- [CoreAudioUtilityClasses](modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/) ([Apple](modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp))
|
||||
- [AudioUnitSDK](modules/juce_audio_plugin_client/AU/AudioUnitSDK/) ([Apache 2.0](modules/juce_audio_plugin_client/AU/AudioUnitSDK/LICENSE.txt))
|
||||
- [AUResources.r](modules/juce_audio_plugin_client/AUResources.r) ([Apple](modules/juce_audio_plugin_client/AUResources.r))
|
||||
- [LV2](modules/juce_audio_processors/format_types/LV2_SDK/) ([ISC](modules/juce_audio_processors/format_types/LV2_SDK/lv2/COPYING))
|
||||
- [pslextensions](modules/juce_audio_processors/format_types/pslextensions/ipslcontextinfo.h) ([Public domain](modules/juce_audio_processors/format_types/pslextensions/ipslcontextinfo.h))
|
||||
|
|
|
|||
|
|
@ -849,7 +849,7 @@ EXCLUDE = build/juce_graphics/image_formats \
|
|||
build/juce_audio_formats/codecs/flac \
|
||||
build/juce_audio_formats/codecs/oggvorbis \
|
||||
build/juce_audio_devices/native \
|
||||
build/juce_audio_plugin_client/AU/CoreAudioUtilityClasses \
|
||||
build/juce_audio_plugin_client/AU/AudioUnitSDK \
|
||||
build/juce_browser_plugin_client/juce_browser_plugin.h \
|
||||
build/juce_core/native \
|
||||
build/juce_events/native \
|
||||
|
|
|
|||
|
|
@ -327,6 +327,8 @@ function(_juce_add_plugin_wrapper_target format path out_path)
|
|||
_juce_link_frameworks("${target_name}" INTERFACE AudioUnit)
|
||||
endif()
|
||||
elseif(format STREQUAL "AU")
|
||||
target_compile_features("${target_name}" INTERFACE cxx_std_17)
|
||||
target_include_directories("${target_name}" INTERFACE "${out_path}/juce_audio_plugin_client/AU")
|
||||
_juce_link_frameworks("${target_name}" INTERFACE AudioUnit CoreAudioKit)
|
||||
endif()
|
||||
endfunction()
|
||||
|
|
|
|||
|
|
@ -87,12 +87,6 @@ set_property(GLOBAL PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD FALSE)
|
|||
if((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD"))
|
||||
_juce_create_pkgconfig_target(JUCE_CURL_LINUX_DEPS libcurl)
|
||||
_juce_create_pkgconfig_target(JUCE_BROWSER_LINUX_DEPS webkit2gtk-4.0 gtk+-x11-3.0)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
find_program(JUCE_XCRUN xcrun)
|
||||
|
||||
if(NOT JUCE_XCRUN)
|
||||
message(WARNING "failed to find xcrun; older resource-based AU plug-ins may not work correctly")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# We set up default/fallback copy dirs here. If you need different copy dirs, use
|
||||
|
|
@ -153,67 +147,6 @@ endfunction()
|
|||
|
||||
# ==================================================================================================
|
||||
|
||||
function(_juce_add_au_resource_fork shared_code_target au_target)
|
||||
if(NOT JUCE_XCRUN)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(product_name ${shared_code_target} JUCE_PRODUCT_NAME)
|
||||
get_target_property(module_sources juce::juce_audio_plugin_client_AU INTERFACE_SOURCES)
|
||||
|
||||
list(FILTER module_sources INCLUDE REGEX "/juce_audio_plugin_client_AU.r$")
|
||||
|
||||
if(NOT module_sources)
|
||||
message(FATAL_ERROR "Failed to find AU resource file input")
|
||||
endif()
|
||||
|
||||
list(GET module_sources 0 au_rez_sources)
|
||||
|
||||
get_target_property(juce_library_code ${shared_code_target} JUCE_GENERATED_SOURCES_DIRECTORY)
|
||||
# We don't want our AU AppConfig.h to end up on peoples' include paths if we can help it
|
||||
set(secret_au_resource_dir "${juce_library_code}/${au_target}/secret")
|
||||
set(secret_au_plugindefines "${secret_au_resource_dir}/JucePluginDefines.h")
|
||||
|
||||
set(au_rez_output "${secret_au_resource_dir}/${product_name}.rsrc")
|
||||
|
||||
target_sources(${au_target} PRIVATE "${au_rez_output}")
|
||||
set_source_files_properties("${au_rez_output}" PROPERTIES
|
||||
GENERATED TRUE
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
set(defs_file $<GENEX_EVAL:$<TARGET_PROPERTY:${shared_code_target},JUCE_DEFS_FILE>>)
|
||||
|
||||
# Passing all our compile definitions using generator expressions is really painful
|
||||
# because some of the definitions have pipes and quotes and dollars and goodness-knows
|
||||
# what else that the shell would very much like to claim for itself, thank you very much.
|
||||
# CMake definitely knows how to escape all these things, because it's perfectly happy to pass
|
||||
# them to compiler invocations, but I have no idea how to get it to escape them
|
||||
# in a custom command.
|
||||
# In the end, it's simplest to generate a special single-purpose appconfig just for the
|
||||
# resource compiler.
|
||||
add_custom_command(OUTPUT "${secret_au_plugindefines}"
|
||||
COMMAND juce::juceaide auplugindefines "${defs_file}" "${secret_au_plugindefines}"
|
||||
DEPENDS "${defs_file}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${au_rez_output}"
|
||||
COMMAND "${JUCE_XCRUN}" Rez
|
||||
-d "ppc_$ppc" -d "i386_$i386" -d "ppc64_$ppc64" -d "x86_64_$x86_64" -d "arm64_$arm64"
|
||||
-I "${secret_au_resource_dir}"
|
||||
-I "/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers"
|
||||
-I "${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/AudioUnit.framework/Headers"
|
||||
-isysroot "${CMAKE_OSX_SYSROOT}"
|
||||
"${au_rez_sources}"
|
||||
-useDF
|
||||
-o "${au_rez_output}"
|
||||
DEPENDS "${secret_au_plugindefines}"
|
||||
VERBATIM)
|
||||
|
||||
set(au_resource_directory "$<TARGET_BUNDLE_DIR:${au_target}>/Contents/Resources")
|
||||
endfunction()
|
||||
|
||||
# ==================================================================================================
|
||||
|
||||
# Ideally, we'd check the preprocessor defs on the target to see whether
|
||||
# JUCE_USE_CURL, JUCE_WEB_BROWSER, or JUCE_IN_APP_PURCHASES have been explicitly turned off,
|
||||
# and then link libraries as appropriate.
|
||||
|
|
@ -1285,10 +1218,6 @@ function(_juce_configure_plugin_targets target)
|
|||
_juce_configure_app_bundle(${target} ${target}_Standalone)
|
||||
endif()
|
||||
|
||||
if(TARGET ${target}_AU)
|
||||
_juce_add_au_resource_fork(${target} ${target}_AU)
|
||||
endif()
|
||||
|
||||
if(TARGET ${target}_AAX)
|
||||
target_link_libraries(${target}_AAX PRIVATE juce_aax_sdk)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1048,7 +1048,7 @@ public:
|
|||
struct XcodeTarget : build_tools::ProjectType::Target
|
||||
{
|
||||
//==============================================================================
|
||||
XcodeTarget (build_tools::ProjectType::Target::Type targetType, const XcodeProjectExporter& exporter)
|
||||
XcodeTarget (Type targetType, const XcodeProjectExporter& exporter)
|
||||
: Target (targetType),
|
||||
owner (exporter)
|
||||
{
|
||||
|
|
@ -1699,10 +1699,17 @@ public:
|
|||
s.set ("CODE_SIGN_ENTITLEMENTS", getEntitlementsFilename().quoted());
|
||||
|
||||
{
|
||||
auto cppStandard = owner.project.getCppStandardString();
|
||||
const auto cppStandard = [&]() -> String
|
||||
{
|
||||
if (owner.project.getCppStandardString() == "latest")
|
||||
return owner.project.getLatestNumberedCppStandardString();
|
||||
|
||||
if (cppStandard == "latest")
|
||||
cppStandard = owner.project.getLatestNumberedCppStandardString();
|
||||
// The AudioUnitSDK requires C++17
|
||||
if (type == AudioUnitPlugIn)
|
||||
return "17";
|
||||
|
||||
return owner.project.getCppStandardString();
|
||||
}();
|
||||
|
||||
s.set ("CLANG_CXX_LANGUAGE_STANDARD", (String (owner.shouldUseGNUExtensions() ? "gnu++"
|
||||
: "c++") + cppStandard).quoted());
|
||||
|
|
@ -1970,10 +1977,15 @@ public:
|
|||
|
||||
if (owner.project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client"))
|
||||
{
|
||||
// Needed to compile .r files
|
||||
paths.add (owner.getModuleFolderRelativeToProject ("juce_audio_plugin_client")
|
||||
.rebased (owner.projectFolder, owner.getTargetFolder(), build_tools::RelativePath::buildTargetFolder)
|
||||
.toUnixStyle());
|
||||
const auto pluginClientModule = owner.getModuleFolderRelativeToProject ("juce_audio_plugin_client");
|
||||
for (const auto& path : { pluginClientModule, // For AU resource fork
|
||||
pluginClientModule.getChildFile ("AU") }) // For AudioUnitSDK includes
|
||||
{
|
||||
paths.add (path.rebased (owner.projectFolder,
|
||||
owner.getTargetFolder(),
|
||||
build_tools::RelativePath::buildTargetFolder)
|
||||
.toUnixStyle());
|
||||
}
|
||||
}
|
||||
|
||||
sanitiseAndEscapeSearchPaths (config, paths);
|
||||
|
|
|
|||
2061
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBase.cpp
Normal file
2061
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBase.cpp
Normal file
File diff suppressed because it is too large
Load diff
733
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBase.h
Normal file
733
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBase.h
Normal file
|
|
@ -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
|
||||
188
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBuffer.cpp
Normal file
188
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBuffer.cpp
Normal file
|
|
@ -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
|
||||
166
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBuffer.h
Normal file
166
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUBuffer.h
Normal file
|
|
@ -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
|
||||
194
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUEffectBase.h
Normal file
194
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUEffectBase.h
Normal file
|
|
@ -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
|
||||
251
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUMIDIBase.cpp
Normal file
251
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUMIDIBase.cpp
Normal file
|
|
@ -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
|
||||
169
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUMIDIBase.h
Normal file
169
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUMIDIBase.h
Normal file
|
|
@ -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
|
||||
524
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUUtility.h
Normal file
524
modules/juce_audio_plugin_client/AU/AudioUnitSDK/AUUtility.h
Normal file
|
|
@ -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
|
||||
162
modules/juce_audio_plugin_client/AU/AudioUnitSDK/ComponentBase.h
Normal file
162
modules/juce_audio_plugin_client/AU/AudioUnitSDK/ComponentBase.h
Normal file
|
|
@ -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
|
||||
202
modules/juce_audio_plugin_client/AU/AudioUnitSDK/LICENSE.txt
Normal file
202
modules/juce_audio_plugin_client/AU/AudioUnitSDK/LICENSE.txt
Normal file
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
File: AUBaseHelper.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUBaseHelper_h__
|
||||
#define __AUBaseHelper_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <AudioUnit/AUComponent.h>
|
||||
#else
|
||||
#include <CoreFoundation.h>
|
||||
#include <AUComponent.h>
|
||||
#endif
|
||||
|
||||
#include "AUBase.h"
|
||||
|
||||
// helpers for dealing with the file-references dictionary in an AUPreset
|
||||
OSStatus GetFileRefPath (CFDictionaryRef parent, CFStringRef frKey, CFStringRef * fPath);
|
||||
|
||||
// if fileRefDict is NULL, this call creates one
|
||||
// if not NULL, then the key value is added to it
|
||||
CFMutableDictionaryRef CreateFileRefDict (CFStringRef fKey, CFStringRef fPath, CFMutableDictionaryRef fileRefDict);
|
||||
|
||||
int AccessURLAsset(const CFURLRef inURL, int mode);
|
||||
|
||||
#if DEBUG
|
||||
void PrintAUParamEvent (AudioUnitParameterEvent& event, FILE* f);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // __AUBaseHelper_h__
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
/*
|
||||
File: AUBuffer.cpp
|
||||
Abstract: AUBuffer.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "AUBuffer.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
AUBufferList::~AUBufferList()
|
||||
{
|
||||
Deallocate();
|
||||
if (mPtrs)
|
||||
free(mPtrs);
|
||||
}
|
||||
|
||||
// a * b + c
|
||||
static UInt32 SafeMultiplyAddUInt32(UInt32 a, UInt32 b, UInt32 c)
|
||||
{
|
||||
if (a == 0 || b == 0) return c; // prevent zero divide
|
||||
|
||||
if (a > (0xFFFFFFFF - c) / b)
|
||||
throw std::bad_alloc();
|
||||
|
||||
return a * b + c;
|
||||
}
|
||||
|
||||
void AUBufferList::Allocate(const CAStreamBasicDescription &format, UInt32 nFrames)
|
||||
{
|
||||
UInt32 nStreams;
|
||||
if (format.IsInterleaved()) {
|
||||
nStreams = 1;
|
||||
} else {
|
||||
nStreams = format.mChannelsPerFrame;
|
||||
}
|
||||
|
||||
// careful -- the I/O thread could be running!
|
||||
if (nStreams > mAllocatedStreams) {
|
||||
size_t theHeaderSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);
|
||||
mPtrs = (AudioBufferList *)CA_realloc(mPtrs,
|
||||
SafeMultiplyAddUInt32(nStreams, sizeof(AudioBuffer), theHeaderSize));
|
||||
mAllocatedStreams = nStreams;
|
||||
}
|
||||
UInt32 bytesPerStream = SafeMultiplyAddUInt32(nFrames, format.mBytesPerFrame, 0xF) & ~0xF;
|
||||
UInt32 nBytes = SafeMultiplyAddUInt32(nStreams, bytesPerStream, 0);
|
||||
if (nBytes > mAllocatedBytes) {
|
||||
if (mExternalMemory) {
|
||||
mExternalMemory = false;
|
||||
mMemory = NULL;
|
||||
}
|
||||
mMemory = (Byte *)CA_realloc(mMemory, nBytes);
|
||||
mAllocatedBytes = nBytes;
|
||||
}
|
||||
mAllocatedFrames = nFrames;
|
||||
mPtrState = kPtrsInvalid;
|
||||
}
|
||||
|
||||
void AUBufferList::Deallocate()
|
||||
{
|
||||
mAllocatedStreams = 0;
|
||||
mAllocatedFrames = 0;
|
||||
mAllocatedBytes = 0;
|
||||
// this causes a world of hurt if someone upstream disconnects during I/O (SysSoundGraph)
|
||||
/* if (mPtrs) {
|
||||
printf("deallocating bufferlist %08X\n", int(mPtrs));
|
||||
free(mPtrs);
|
||||
mPtrs = NULL;
|
||||
} */
|
||||
if (mMemory) {
|
||||
if (mExternalMemory)
|
||||
mExternalMemory = false;
|
||||
else
|
||||
free(mMemory);
|
||||
mMemory = NULL;
|
||||
}
|
||||
mPtrState = kPtrsInvalid;
|
||||
}
|
||||
|
||||
AudioBufferList & AUBufferList::PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames)
|
||||
{
|
||||
if (nFrames > mAllocatedFrames)
|
||||
COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess);
|
||||
|
||||
UInt32 nStreams;
|
||||
UInt32 channelsPerStream;
|
||||
if (format.IsInterleaved()) {
|
||||
nStreams = 1;
|
||||
channelsPerStream = format.mChannelsPerFrame;
|
||||
} else {
|
||||
nStreams = format.mChannelsPerFrame;
|
||||
channelsPerStream = 1;
|
||||
if (nStreams > mAllocatedStreams)
|
||||
COMPONENT_THROW(kAudioUnitErr_FormatNotSupported);
|
||||
}
|
||||
|
||||
AudioBufferList *abl = mPtrs;
|
||||
abl->mNumberBuffers = nStreams;
|
||||
AudioBuffer *buf = abl->mBuffers;
|
||||
Byte *mem = mMemory;
|
||||
UInt32 streamInterval = (mAllocatedFrames * format.mBytesPerFrame + 0xF) & ~0xF;
|
||||
UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame;
|
||||
for ( ; nStreams--; ++buf) {
|
||||
buf->mNumberChannels = channelsPerStream;
|
||||
buf->mData = mem;
|
||||
buf->mDataByteSize = bytesPerBuffer;
|
||||
mem += streamInterval;
|
||||
}
|
||||
if (UInt32(mem - mMemory) > mAllocatedBytes)
|
||||
COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess);
|
||||
mPtrState = kPtrsToMyMemory;
|
||||
return *mPtrs;
|
||||
}
|
||||
|
||||
AudioBufferList & AUBufferList::PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames)
|
||||
{
|
||||
UInt32 nStreams;
|
||||
UInt32 channelsPerStream;
|
||||
if (format.IsInterleaved()) {
|
||||
nStreams = 1;
|
||||
channelsPerStream = format.mChannelsPerFrame;
|
||||
} else {
|
||||
nStreams = format.mChannelsPerFrame;
|
||||
channelsPerStream = 1;
|
||||
if (nStreams > mAllocatedStreams)
|
||||
COMPONENT_THROW(kAudioUnitErr_FormatNotSupported);
|
||||
}
|
||||
AudioBufferList *abl = mPtrs;
|
||||
abl->mNumberBuffers = nStreams;
|
||||
AudioBuffer *buf = abl->mBuffers;
|
||||
UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame;
|
||||
for ( ; nStreams--; ++buf) {
|
||||
buf->mNumberChannels = channelsPerStream;
|
||||
buf->mData = NULL;
|
||||
buf->mDataByteSize = bytesPerBuffer;
|
||||
}
|
||||
mPtrState = kPtrsToExternalMemory;
|
||||
return *mPtrs;
|
||||
}
|
||||
|
||||
// this should NOT be called while I/O is in process
|
||||
void AUBufferList::UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf)
|
||||
{
|
||||
UInt32 alignedSize = buf.size & ~0xF;
|
||||
if (mMemory != NULL && alignedSize >= mAllocatedBytes) {
|
||||
// don't accept the buffer if we already have one and it's big enough
|
||||
// if we don't already have one, we don't need one
|
||||
Byte *oldMemory = mMemory;
|
||||
mMemory = buf.buffer;
|
||||
mAllocatedBytes = alignedSize;
|
||||
// from Allocate(): nBytes = nStreams * nFrames * format.mBytesPerFrame;
|
||||
// thus: nFrames = nBytes / (nStreams * format.mBytesPerFrame)
|
||||
mAllocatedFrames = mAllocatedBytes / (format.NumberChannelStreams() * format.mBytesPerFrame);
|
||||
mExternalMemory = true;
|
||||
free(oldMemory);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void AUBufferList::PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames, bool asFloats)
|
||||
{
|
||||
printf(" %s [%d] 0x%08lX:\n", label, subscript, long(&abl));
|
||||
const AudioBuffer *buf = abl.mBuffers;
|
||||
for (UInt32 i = 0; i < abl.mNumberBuffers; ++buf, ++i) {
|
||||
printf(" [%2d] %5dbytes %dch @ %p: ", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData);
|
||||
if (buf->mData != NULL) {
|
||||
UInt32 nSamples = nFrames * buf->mNumberChannels;
|
||||
for (UInt32 j = 0; j < nSamples; ++j) {
|
||||
if (nSamples > 16 && (j % 16) == 0)
|
||||
printf("\n\t");
|
||||
if (asFloats)
|
||||
printf(" %6.3f", ((float *)buf->mData)[j]);
|
||||
else
|
||||
printf(" %08X", (unsigned)((UInt32 *)buf->mData)[j]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
File: AUBuffer.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUBuffer_h__
|
||||
#define __AUBuffer_h__
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#else
|
||||
#include <AudioUnit.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
// make this usable outside the stricter context of AudiUnits
|
||||
#ifndef COMPONENT_THROW
|
||||
#define COMPONENT_THROW(err) \
|
||||
do { DebugMessage(#err); throw static_cast<OSStatus>(err); } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*! @class AUBufferList */
|
||||
class AUBufferList {
|
||||
enum EPtrState {
|
||||
kPtrsInvalid,
|
||||
kPtrsToMyMemory,
|
||||
kPtrsToExternalMemory
|
||||
};
|
||||
public:
|
||||
/*! @ctor AUBufferList */
|
||||
AUBufferList() : mPtrState(kPtrsInvalid), mExternalMemory(false), mPtrs(NULL), mMemory(NULL),
|
||||
mAllocatedStreams(0), mAllocatedFrames(0), mAllocatedBytes(0) { }
|
||||
/*! @dtor ~AUBufferList */
|
||||
~AUBufferList();
|
||||
|
||||
/*! @method PrepareBuffer */
|
||||
AudioBufferList & PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames);
|
||||
/*! @method PrepareNullBuffer */
|
||||
AudioBufferList & PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames);
|
||||
|
||||
/*! @method SetBufferList */
|
||||
AudioBufferList & SetBufferList(const AudioBufferList &abl) {
|
||||
if (mAllocatedStreams < abl.mNumberBuffers)
|
||||
COMPONENT_THROW(-1);
|
||||
mPtrState = kPtrsToExternalMemory;
|
||||
memcpy(mPtrs, &abl, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl);
|
||||
return *mPtrs;
|
||||
}
|
||||
|
||||
/*! @method SetBuffer */
|
||||
void SetBuffer(UInt32 index, const AudioBuffer &ab) {
|
||||
if (mPtrState == kPtrsInvalid || index >= mPtrs->mNumberBuffers)
|
||||
COMPONENT_THROW(-1);
|
||||
mPtrState = kPtrsToExternalMemory;
|
||||
mPtrs->mBuffers[index] = ab;
|
||||
}
|
||||
|
||||
/*! @method InvalidateBufferList */
|
||||
void InvalidateBufferList() { mPtrState = kPtrsInvalid; }
|
||||
|
||||
/*! @method GetBufferList */
|
||||
AudioBufferList & GetBufferList() const {
|
||||
if (mPtrState == kPtrsInvalid)
|
||||
COMPONENT_THROW(-1);
|
||||
return *mPtrs;
|
||||
}
|
||||
|
||||
/*! @method CopyBufferListTo */
|
||||
void CopyBufferListTo(AudioBufferList &abl) const {
|
||||
if (mPtrState == kPtrsInvalid)
|
||||
COMPONENT_THROW(-1);
|
||||
memcpy(&abl, mPtrs, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl);
|
||||
}
|
||||
|
||||
/*! @method CopyBufferContentsTo */
|
||||
void CopyBufferContentsTo(AudioBufferList &abl) const {
|
||||
if (mPtrState == kPtrsInvalid)
|
||||
COMPONENT_THROW(-1);
|
||||
const AudioBuffer *srcbuf = mPtrs->mBuffers;
|
||||
AudioBuffer *destbuf = abl.mBuffers;
|
||||
|
||||
for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) {
|
||||
if (i >= mPtrs->mNumberBuffers) // duplicate last source to additional outputs [4341137]
|
||||
--srcbuf;
|
||||
if (destbuf->mData != srcbuf->mData)
|
||||
memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
|
||||
destbuf->mDataByteSize = srcbuf->mDataByteSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @method Allocate */
|
||||
void Allocate(const CAStreamBasicDescription &format, UInt32 nFrames);
|
||||
/*! @method Deallocate */
|
||||
void Deallocate();
|
||||
|
||||
/*! @method UseExternalBuffer */
|
||||
void UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf);
|
||||
|
||||
// AudioBufferList utilities
|
||||
/*! @method ZeroBuffer */
|
||||
static void ZeroBuffer(AudioBufferList &abl) {
|
||||
AudioBuffer *buf = abl.mBuffers;
|
||||
for (UInt32 i = abl.mNumberBuffers ; i--; ++buf)
|
||||
memset(buf->mData, 0, buf->mDataByteSize);
|
||||
}
|
||||
#if DEBUG
|
||||
/*! @method PrintBuffer */
|
||||
static void PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames = 8, bool asFloats = true);
|
||||
#endif
|
||||
|
||||
/*! @method GetAllocatedFrames */
|
||||
UInt32 GetAllocatedFrames() const { return mAllocatedFrames; }
|
||||
|
||||
private:
|
||||
/*! @ctor AUBufferList */
|
||||
AUBufferList(AUBufferList &) { } // prohibit copy constructor
|
||||
|
||||
/*! @var mPtrState */
|
||||
EPtrState mPtrState;
|
||||
/*! @var mExternalMemory */
|
||||
bool mExternalMemory;
|
||||
/*! @var mPtrs */
|
||||
AudioBufferList * mPtrs;
|
||||
/*! @var mMemory */
|
||||
Byte * mMemory;
|
||||
/*! @var mAllocatedStreams */
|
||||
UInt32 mAllocatedStreams;
|
||||
/*! @var mAllocatedFrames */
|
||||
UInt32 mAllocatedFrames;
|
||||
/*! @var mAllocatedBytes */
|
||||
UInt32 mAllocatedBytes;
|
||||
};
|
||||
|
||||
|
||||
// Allocates an array of samples (type T), to be optimally aligned for the processor
|
||||
/*! @class TAUBuffer */
|
||||
template <class T>
|
||||
class TAUBuffer {
|
||||
public:
|
||||
enum {
|
||||
kAlignInterval = 0x10,
|
||||
kAlignMask = kAlignInterval - 1
|
||||
};
|
||||
|
||||
/*! @ctor TAUBuffer.0 */
|
||||
TAUBuffer() : mMemObject(NULL), mAlignedBuffer(NULL), mBufferSizeBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*! @ctor TAUBuffer.1 */
|
||||
TAUBuffer(UInt32 numElems, UInt32 numChannels) : mMemObject(NULL), mAlignedBuffer(NULL),
|
||||
mBufferSizeBytes(0)
|
||||
{
|
||||
Allocate(numElems, numChannels);
|
||||
}
|
||||
|
||||
/*! @dtor ~TAUBuffer */
|
||||
~TAUBuffer()
|
||||
{
|
||||
Deallocate();
|
||||
}
|
||||
|
||||
/*! @method Allocate */
|
||||
void Allocate(UInt32 numElems) // can also re-allocate
|
||||
{
|
||||
UInt32 reqSize = numElems * sizeof(T);
|
||||
|
||||
if (mMemObject != NULL && reqSize == mBufferSizeBytes)
|
||||
return; // already allocated
|
||||
|
||||
mBufferSizeBytes = reqSize;
|
||||
mMemObject = CA_realloc(mMemObject, reqSize);
|
||||
UInt32 misalign = (uintptr_t)mMemObject & kAlignMask;
|
||||
if (misalign) {
|
||||
mMemObject = CA_realloc(mMemObject, reqSize + kAlignMask);
|
||||
mAlignedBuffer = (T *)((char *)mMemObject + kAlignInterval - misalign);
|
||||
} else
|
||||
mAlignedBuffer = (T *)mMemObject;
|
||||
}
|
||||
|
||||
/*! @method Deallocate */
|
||||
void Deallocate()
|
||||
{
|
||||
if (mMemObject == NULL) return; // so this method has no effect if we're using
|
||||
// an external buffer
|
||||
|
||||
free(mMemObject);
|
||||
mMemObject = NULL;
|
||||
mAlignedBuffer = NULL;
|
||||
mBufferSizeBytes = 0;
|
||||
}
|
||||
|
||||
/*! @method AllocateClear */
|
||||
void AllocateClear(UInt32 numElems) // can also re-allocate
|
||||
{
|
||||
Allocate(numElems);
|
||||
Clear();
|
||||
}
|
||||
|
||||
/*! @method Clear */
|
||||
void Clear()
|
||||
{
|
||||
memset(mAlignedBuffer, 0, mBufferSizeBytes);
|
||||
}
|
||||
|
||||
// accessors
|
||||
|
||||
/*! @method operator T *()@ */
|
||||
operator T *() { return mAlignedBuffer; }
|
||||
|
||||
private:
|
||||
/*! @var mMemObject */
|
||||
void * mMemObject; // null when using an external buffer
|
||||
/*! @var mAlignedBuffer */
|
||||
T * mAlignedBuffer; // always valid once allocated
|
||||
/*! @var mBufferSizeBytes */
|
||||
UInt32 mBufferSizeBytes;
|
||||
};
|
||||
|
||||
#endif // __AUBuffer_h__
|
||||
|
|
@ -1,438 +0,0 @@
|
|||
/*
|
||||
File: AUDispatch.cpp
|
||||
Abstract: AUDispatch.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "AUBase.h"
|
||||
#include "CAXException.h"
|
||||
#include "AUDispatch.h"
|
||||
|
||||
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#if __LP64__
|
||||
// comp instance, parameters in forward order
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_index + 1];
|
||||
#else
|
||||
// parameters in reverse order, then comp instance
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index];
|
||||
#endif
|
||||
#elif TARGET_OS_WIN32
|
||||
// (no comp instance), parameters in forward order
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_index];
|
||||
#endif
|
||||
|
||||
|
||||
OSStatus AUBase::ComponentEntryDispatch(ComponentParameters *params, AUBase *This)
|
||||
{
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
|
||||
OSStatus result = noErr;
|
||||
|
||||
switch (params->what) {
|
||||
case kComponentCanDoSelect:
|
||||
switch (GetSelectorForCanDo(params)) {
|
||||
// any selectors
|
||||
case kAudioUnitInitializeSelect:
|
||||
case kAudioUnitUninitializeSelect:
|
||||
case kAudioUnitGetPropertyInfoSelect:
|
||||
case kAudioUnitGetPropertySelect:
|
||||
case kAudioUnitSetPropertySelect:
|
||||
case kAudioUnitAddPropertyListenerSelect:
|
||||
#if (!__LP64__)
|
||||
case kAudioUnitRemovePropertyListenerSelect:
|
||||
#endif
|
||||
case kAudioUnitGetParameterSelect:
|
||||
case kAudioUnitSetParameterSelect:
|
||||
case kAudioUnitResetSelect:
|
||||
result = 1;
|
||||
break;
|
||||
// v1 selectors
|
||||
|
||||
// v2 selectors
|
||||
case kAudioUnitRemovePropertyListenerWithUserDataSelect:
|
||||
case kAudioUnitAddRenderNotifySelect:
|
||||
case kAudioUnitRemoveRenderNotifySelect:
|
||||
case kAudioUnitScheduleParametersSelect:
|
||||
case kAudioUnitRenderSelect:
|
||||
result = (This->AudioUnitAPIVersion() > 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return ComponentBase::ComponentEntryDispatch(params, This);
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitInitializeSelect:
|
||||
{
|
||||
CAMutex::Locker lock2(This->GetMutex());
|
||||
result = This->DoInitialize();
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitUninitializeSelect:
|
||||
{
|
||||
CAMutex::Locker lock2(This->GetMutex());
|
||||
This->DoCleanup();
|
||||
result = noErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitGetPropertyInfoSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitPropertyID, pinID, 0, 5);
|
||||
PARAM(AudioUnitScope, pinScope, 1, 5);
|
||||
PARAM(AudioUnitElement, pinElement, 2, 5);
|
||||
PARAM(UInt32 *, poutDataSize, 3, 5);
|
||||
PARAM(Boolean *, poutWritable, 4, 5);
|
||||
|
||||
// pass our own copies so that we assume responsibility for testing
|
||||
// the caller's pointers against null and our C++ classes can
|
||||
// always assume they're non-null
|
||||
UInt32 dataSize;
|
||||
Boolean writable;
|
||||
|
||||
result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable);
|
||||
if (poutDataSize != NULL)
|
||||
*poutDataSize = dataSize;
|
||||
if (poutWritable != NULL)
|
||||
*poutWritable = writable;
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitGetPropertySelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitPropertyID, pinID, 0, 5);
|
||||
PARAM(AudioUnitScope, pinScope, 1, 5);
|
||||
PARAM(AudioUnitElement, pinElement, 2, 5);
|
||||
PARAM(void *, poutData, 3, 5);
|
||||
PARAM(UInt32 *, pioDataSize, 4, 5);
|
||||
|
||||
UInt32 actualPropertySize, clientBufferSize;
|
||||
Boolean writable;
|
||||
char *tempBuffer;
|
||||
void *destBuffer;
|
||||
|
||||
if (pioDataSize == NULL) {
|
||||
ca_debug_string("AudioUnitGetProperty: null size pointer");
|
||||
result = kAudio_ParamError;
|
||||
goto finishGetProperty;
|
||||
}
|
||||
if (poutData == NULL) {
|
||||
UInt32 dataSize;
|
||||
|
||||
result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable);
|
||||
*pioDataSize = dataSize;
|
||||
goto finishGetProperty;
|
||||
}
|
||||
|
||||
clientBufferSize = *pioDataSize;
|
||||
if (clientBufferSize == 0)
|
||||
{
|
||||
ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry");
|
||||
// $$$ or should we allow this as a shortcut for finding the size?
|
||||
result = kAudio_ParamError;
|
||||
goto finishGetProperty;
|
||||
}
|
||||
|
||||
result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement,
|
||||
actualPropertySize, writable);
|
||||
if (result)
|
||||
goto finishGetProperty;
|
||||
|
||||
if (clientBufferSize < actualPropertySize)
|
||||
{
|
||||
tempBuffer = new char[actualPropertySize];
|
||||
destBuffer = tempBuffer;
|
||||
} else {
|
||||
tempBuffer = NULL;
|
||||
destBuffer = poutData;
|
||||
}
|
||||
|
||||
result = This->DispatchGetProperty(pinID, pinScope, pinElement, destBuffer);
|
||||
|
||||
if (result == noErr) {
|
||||
if (clientBufferSize < actualPropertySize && tempBuffer != NULL)
|
||||
{
|
||||
memcpy(poutData, tempBuffer, clientBufferSize);
|
||||
delete[] tempBuffer;
|
||||
// pioDataSize remains correct, the number of bytes we wrote
|
||||
} else
|
||||
*pioDataSize = actualPropertySize;
|
||||
} else
|
||||
*pioDataSize = 0;
|
||||
|
||||
finishGetProperty:
|
||||
;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitSetPropertySelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitPropertyID, pinID, 0, 5);
|
||||
PARAM(AudioUnitScope, pinScope, 1, 5);
|
||||
PARAM(AudioUnitElement, pinElement, 2, 5);
|
||||
PARAM(const void *, pinData, 3, 5);
|
||||
PARAM(UInt32, pinDataSize, 4, 5);
|
||||
|
||||
if (pinData && pinDataSize)
|
||||
result = This->DispatchSetProperty(pinID, pinScope, pinElement, pinData, pinDataSize);
|
||||
else {
|
||||
if (pinData == NULL && pinDataSize == 0) {
|
||||
result = This->DispatchRemovePropertyValue (pinID, pinScope, pinElement);
|
||||
} else {
|
||||
if (pinData == NULL) {
|
||||
ca_debug_string("AudioUnitSetProperty: inData == NULL");
|
||||
result = kAudio_ParamError;
|
||||
goto finishSetProperty;
|
||||
}
|
||||
|
||||
if (pinDataSize == 0) {
|
||||
ca_debug_string("AudioUnitSetProperty: inDataSize == 0");
|
||||
result = kAudio_ParamError;
|
||||
goto finishSetProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
finishSetProperty:
|
||||
;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitAddPropertyListenerSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitPropertyID, pinID, 0, 3);
|
||||
PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3);
|
||||
PARAM(void *, pinProcRefCon, 2, 3);
|
||||
result = This->AddPropertyListener(pinID, pinProc, pinProcRefCon);
|
||||
}
|
||||
break;
|
||||
|
||||
#if (!__LP64__)
|
||||
case kAudioUnitRemovePropertyListenerSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitPropertyID, pinID, 0, 2);
|
||||
PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 2);
|
||||
result = This->RemovePropertyListener(pinID, pinProc, NULL, false);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case kAudioUnitRemovePropertyListenerWithUserDataSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitPropertyID, pinID, 0, 3);
|
||||
PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3);
|
||||
PARAM(void *, pinProcRefCon, 2, 3);
|
||||
result = This->RemovePropertyListener(pinID, pinProc, pinProcRefCon, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitAddRenderNotifySelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AURenderCallback, pinProc, 0, 2);
|
||||
PARAM(void *, pinProcRefCon, 1, 2);
|
||||
result = This->SetRenderNotification (pinProc, pinProcRefCon);
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitRemoveRenderNotifySelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AURenderCallback, pinProc, 0, 2);
|
||||
PARAM(void *, pinProcRefCon, 1, 2);
|
||||
result = This->RemoveRenderNotification (pinProc, pinProcRefCon);
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitGetParameterSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitParameterID, pinID, 0, 4);
|
||||
PARAM(AudioUnitScope, pinScope, 1, 4);
|
||||
PARAM(AudioUnitElement, pinElement, 2, 4);
|
||||
PARAM(AudioUnitParameterValue *, poutValue, 3, 4);
|
||||
result = (poutValue == NULL ? kAudio_ParamError : This->GetParameter(pinID, pinScope, pinElement, *poutValue));
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitSetParameterSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex()); // is this realtime or no???
|
||||
PARAM(AudioUnitParameterID, pinID, 0, 5);
|
||||
PARAM(AudioUnitScope, pinScope, 1, 5);
|
||||
PARAM(AudioUnitElement, pinElement, 2, 5);
|
||||
PARAM(AudioUnitParameterValue, pinValue, 3, 5);
|
||||
PARAM(UInt32, pinBufferOffsetInFrames, 4, 5);
|
||||
result = This->SetParameter(pinID, pinScope, pinElement, pinValue, pinBufferOffsetInFrames);
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitScheduleParametersSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex()); // is this realtime or no???
|
||||
if (This->AudioUnitAPIVersion() > 1)
|
||||
{
|
||||
PARAM(AudioUnitParameterEvent *, pinParameterEvent, 0, 2);
|
||||
PARAM(UInt32, pinNumParamEvents, 1, 2);
|
||||
result = This->ScheduleParameter (pinParameterEvent, pinNumParamEvents);
|
||||
} else
|
||||
result = badComponentSelector;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case kAudioUnitRenderSelect:
|
||||
{
|
||||
// realtime; no lock
|
||||
{
|
||||
PARAM(AudioUnitRenderActionFlags *, pinActionFlags, 0, 5);
|
||||
PARAM(const AudioTimeStamp *, pinTimeStamp, 1, 5);
|
||||
PARAM(UInt32, pinOutputBusNumber, 2, 5);
|
||||
PARAM(UInt32, pinNumberFrames, 3, 5);
|
||||
PARAM(AudioBufferList *, pioData, 4, 5);
|
||||
AudioUnitRenderActionFlags tempFlags;
|
||||
|
||||
if (pinTimeStamp == NULL || pioData == NULL)
|
||||
result = kAudio_ParamError;
|
||||
else {
|
||||
if (pinActionFlags == NULL) {
|
||||
tempFlags = 0;
|
||||
pinActionFlags = &tempFlags;
|
||||
}
|
||||
result = This->DoRender(*pinActionFlags, *pinTimeStamp, pinOutputBusNumber, pinNumberFrames, *pioData);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioUnitResetSelect:
|
||||
{
|
||||
CAMutex::Locker lock(This->GetMutex());
|
||||
PARAM(AudioUnitScope, pinScope, 0, 2);
|
||||
PARAM(AudioUnitElement, pinElement, 1, 2);
|
||||
This->ResetRenderTime();
|
||||
result = This->Reset(pinScope, pinElement);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = ComponentBase::ComponentEntryDispatch(params, This);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Fast dispatch entry points -- these need to replicate all error-checking logic from above
|
||||
|
||||
OSStatus CMgr_AudioUnitBaseGetParameter( AUBase * This,
|
||||
AudioUnitParameterID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
float *outValue)
|
||||
{
|
||||
OSStatus result = AUBase::noErr;
|
||||
|
||||
try {
|
||||
if (This == NULL || outValue == NULL) return kAudio_ParamError;
|
||||
result = This->GetParameter(inID, inScope, inElement, *outValue);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus CMgr_AudioUnitBaseSetParameter( AUBase * This,
|
||||
AudioUnitParameterID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
float inValue,
|
||||
UInt32 inBufferOffset)
|
||||
{
|
||||
OSStatus result = AUBase::noErr;
|
||||
|
||||
try {
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
result = This->SetParameter(inID, inScope, inElement, inValue, inBufferOffset);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus CMgr_AudioUnitBaseRender( AUBase * This,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp * inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList * ioData)
|
||||
{
|
||||
if (inTimeStamp == NULL || ioData == NULL) return kAudio_ParamError;
|
||||
|
||||
OSStatus result = AUBase::noErr;
|
||||
AudioUnitRenderActionFlags tempFlags;
|
||||
|
||||
try {
|
||||
if (ioActionFlags == NULL) {
|
||||
tempFlags = 0;
|
||||
ioActionFlags = &tempFlags;
|
||||
}
|
||||
result = This->DoRender(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, *ioData);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
File: AUDispatch.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUDispatch_h__
|
||||
#define __AUDispatch_h__
|
||||
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#else
|
||||
#include "AudioUnit.h"
|
||||
#endif
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
/*! @function AudioUnitBaseGetParameter */
|
||||
OSStatus CMgr_AudioUnitBaseGetParameter( AUBase * This,
|
||||
AudioUnitParameterID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
float * outValue);
|
||||
|
||||
/*! @function AudioUnitBaseSetParameter */
|
||||
OSStatus CMgr_AudioUnitBaseSetParameter( AUBase * This,
|
||||
AudioUnitParameterID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
float inValue,
|
||||
UInt32 inBufferOffset);
|
||||
|
||||
/*! @function AudioUnitBaseRender */
|
||||
OSStatus CMgr_AudioUnitBaseRender( AUBase * This,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp * inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList * ioData);
|
||||
#endif
|
||||
|
||||
#endif // __AUDispatch_h__
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
File: AUInputElement.cpp
|
||||
Abstract: AUInputElement.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "AUBase.h"
|
||||
|
||||
inline bool HasGoodBufferPointers(const AudioBufferList &abl, UInt32 nBytes)
|
||||
{
|
||||
const AudioBuffer *buf = abl.mBuffers;
|
||||
for (UInt32 i = abl.mNumberBuffers; i--;++buf) {
|
||||
if (buf->mData == NULL || buf->mDataByteSize < nBytes)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUInputElement::AUInputElement
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
AUInputElement::AUInputElement(AUBase *audioUnit) :
|
||||
AUIOElement(audioUnit),
|
||||
mInputType(kNoInput)
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUInputElement::SetConnection
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void AUInputElement::SetConnection(const AudioUnitConnection &conn)
|
||||
{
|
||||
if (conn.sourceAudioUnit == 0) {
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
mInputType = kFromConnection;
|
||||
mConnection = conn;
|
||||
AllocateBuffer();
|
||||
|
||||
mConnInstanceStorage = NULL;
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
mConnRenderProc = NULL;
|
||||
UInt32 size = sizeof(AudioUnitRenderProc);
|
||||
OSStatus result = AudioUnitGetProperty( conn.sourceAudioUnit,
|
||||
kAudioUnitProperty_FastDispatch,
|
||||
kAudioUnitScope_Global,
|
||||
kAudioUnitRenderSelect,
|
||||
&mConnRenderProc,
|
||||
&size);
|
||||
if (result == noErr)
|
||||
mConnInstanceStorage = CMgr_GetComponentInstanceStorage (conn.sourceAudioUnit);
|
||||
else
|
||||
mConnRenderProc = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AUInputElement::Disconnect()
|
||||
{
|
||||
mInputType = kNoInput;
|
||||
mIOBuffer.Deallocate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUInputElement::SetInputCallback
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void AUInputElement::SetInputCallback(AURenderCallback proc, void *refCon)
|
||||
{
|
||||
if (proc == NULL)
|
||||
Disconnect();
|
||||
else {
|
||||
mInputType = kFromCallback;
|
||||
mInputProc = proc;
|
||||
mInputProcRefCon = refCon;
|
||||
AllocateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus AUInputElement::SetStreamFormat(const CAStreamBasicDescription &fmt)
|
||||
{
|
||||
OSStatus err = AUIOElement::SetStreamFormat(fmt);
|
||||
if (err == AUBase::noErr)
|
||||
AllocateBuffer();
|
||||
return err;
|
||||
}
|
||||
|
||||
OSStatus AUInputElement::PullInput( AudioUnitRenderActionFlags & ioActionFlags,
|
||||
const AudioTimeStamp & inTimeStamp,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 nFrames)
|
||||
{
|
||||
if (!IsActive())
|
||||
return kAudioUnitErr_NoConnection;
|
||||
|
||||
AudioBufferList *pullBuffer;
|
||||
|
||||
if (HasConnection() || !WillAllocateBuffer())
|
||||
pullBuffer = &mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames);
|
||||
else
|
||||
pullBuffer = &mIOBuffer.PrepareBuffer(mStreamFormat, nFrames);
|
||||
|
||||
return PullInputWithBufferList (ioActionFlags, inTimeStamp, inElement, nFrames, pullBuffer);
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
File: AUInputElement.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUInput_h__
|
||||
#define __AUInput_h__
|
||||
|
||||
#include "AUScopeElement.h"
|
||||
#include "AUBuffer.h"
|
||||
|
||||
/*! @class AUInputElement */
|
||||
class AUInputElement : public AUIOElement {
|
||||
public:
|
||||
|
||||
/*! @ctor AUInputElement */
|
||||
AUInputElement(AUBase *audioUnit);
|
||||
/*! @dtor ~AUInputElement */
|
||||
virtual ~AUInputElement() { }
|
||||
|
||||
// AUElement override
|
||||
/*! @method SetStreamFormat */
|
||||
virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
|
||||
/*! @method NeedsBufferSpace */
|
||||
virtual bool NeedsBufferSpace() const { return IsCallback(); }
|
||||
|
||||
/*! @method SetConnection */
|
||||
void SetConnection(const AudioUnitConnection &conn);
|
||||
/*! @method SetInputCallback */
|
||||
void SetInputCallback(AURenderCallback proc, void *refCon);
|
||||
|
||||
/*! @method IsActive */
|
||||
bool IsActive() const { return mInputType != kNoInput; }
|
||||
/*! @method IsCallback */
|
||||
bool IsCallback() const { return mInputType == kFromCallback; }
|
||||
/*! @method HasConnection */
|
||||
bool HasConnection() const { return mInputType == kFromConnection; }
|
||||
|
||||
/*! @method PullInput */
|
||||
OSStatus PullInput( AudioUnitRenderActionFlags & ioActionFlags,
|
||||
const AudioTimeStamp & inTimeStamp,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 inNumberFrames);
|
||||
|
||||
/*! @method PullInputWithBufferList */
|
||||
OSStatus PullInputWithBufferList( AudioUnitRenderActionFlags & ioActionFlags,
|
||||
const AudioTimeStamp & inTimeStamp,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 nFrames,
|
||||
AudioBufferList * inBufferList);
|
||||
protected:
|
||||
/*! @method Disconnect */
|
||||
void Disconnect();
|
||||
|
||||
enum EInputType { kNoInput, kFromConnection, kFromCallback };
|
||||
|
||||
/*! @var mInputType */
|
||||
EInputType mInputType;
|
||||
|
||||
// if from callback:
|
||||
/*! @var mInputProc */
|
||||
AURenderCallback mInputProc;
|
||||
/*! @var mInputProcRefCon */
|
||||
void * mInputProcRefCon;
|
||||
|
||||
// if from connection:
|
||||
/*! @var mConnection */
|
||||
AudioUnitConnection mConnection;
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
/*! @var mConnRenderProc */
|
||||
AudioUnitRenderProc mConnRenderProc;
|
||||
#endif
|
||||
/*! @var mConnInstanceStorage */
|
||||
void * mConnInstanceStorage; // for the input component
|
||||
};
|
||||
|
||||
|
||||
#endif // __AUInput_h__
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
File: AUInputFormatConverter.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUInputFormatConverter_h__
|
||||
#define __AUInputFormatConverter_h__
|
||||
|
||||
#include "FormatConverterClient.h"
|
||||
#include "AUTimestampGenerator.h"
|
||||
|
||||
// ____________________________________________________________________________
|
||||
// AUInputFormatConverter
|
||||
//
|
||||
// Subclass of FormatConverterClient that applies a format conversion
|
||||
// to an input of an AudioUnit.
|
||||
/*! @class AUInputFormatConverter */
|
||||
class AUInputFormatConverter : public FormatConverterClient {
|
||||
public:
|
||||
/*! @ctor AUInputFormatConverter */
|
||||
AUInputFormatConverter(AUBase *hostAU, int inputBus) :
|
||||
mHost(hostAU),
|
||||
mHostBus(inputBus),
|
||||
mPreviousSilentFrames(0x1000)
|
||||
{
|
||||
#if DEBUG
|
||||
mTimestampGenerator.mVerbosity = 0;
|
||||
strcpy(mTimestampGenerator.mDebugName, "AUConverter");
|
||||
#endif
|
||||
}
|
||||
|
||||
// need to subsequently call Initialize, with the desired formats
|
||||
|
||||
/*! @dtor ~AUInputFormatConverter */
|
||||
~AUInputFormatConverter()
|
||||
{
|
||||
}
|
||||
|
||||
virtual OSStatus Initialize(const AudioStreamBasicDescription &src, const AudioStreamBasicDescription &dest)
|
||||
{
|
||||
OSStatus err = FormatConverterClient::Initialize(src, dest);
|
||||
if (err) return err;
|
||||
mIsPCMToPCM = (src.mFormatID == kAudioFormatLinearPCM) && (dest.mFormatID == kAudioFormatLinearPCM);
|
||||
mHasSRC = (fnonzero(src.mSampleRate) && fnonzero(dest.mSampleRate) && fnotequal(src.mSampleRate, dest.mSampleRate));
|
||||
return ca_noErr;
|
||||
}
|
||||
|
||||
virtual OSStatus Reset()
|
||||
{
|
||||
mPreviousSilentFrames = 0x1000;
|
||||
mTimestampGenerator.Reset();
|
||||
return FormatConverterClient::Reset();
|
||||
}
|
||||
|
||||
void SetStartInputTimeAtZero(bool b)
|
||||
{
|
||||
mTimestampGenerator.SetStartInputAtZero(b);
|
||||
}
|
||||
|
||||
/*! @method FillComplexBuffer */
|
||||
OSStatus AUFillComplexBuffer(const AudioTimeStamp & inTimeStamp,
|
||||
UInt32 & ioOutputDataPacketSize,
|
||||
AudioBufferList & outOutputData,
|
||||
AudioStreamPacketDescription* outPacketDescription,
|
||||
bool& outSilence)
|
||||
{
|
||||
mTimestampGenerator.AddOutputTime(inTimeStamp, ioOutputDataPacketSize, mOutputFormat.mSampleRate);
|
||||
mSilentOutput = true;
|
||||
OSStatus err = FillComplexBuffer(ioOutputDataPacketSize, outOutputData, outPacketDescription);
|
||||
if (mSilentOutput) {
|
||||
if (!mIsPCMToPCM || (mHasSRC && mPreviousSilentFrames < 32))
|
||||
mSilentOutput = false;
|
||||
mPreviousSilentFrames += ioOutputDataPacketSize;
|
||||
} else
|
||||
mPreviousSilentFrames = 0;
|
||||
outSilence = mSilentOutput;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*! @method FormatConverterInputProc */
|
||||
virtual OSStatus FormatConverterInputProc(
|
||||
UInt32 & ioNumberDataPackets,
|
||||
AudioBufferList & ioData,
|
||||
AudioStreamPacketDescription** outDataPacketDescription)
|
||||
{
|
||||
OSStatus err = ca_noErr;
|
||||
|
||||
AudioUnitRenderActionFlags actionFlags = 0;
|
||||
AUInputElement *input = mHost->GetInput(mHostBus);
|
||||
*ioNumberDataPackets = std::min(*ioNumberDataPackets, This->mHost->GetMaxFramesPerSlice());
|
||||
const AudioTimeStamp &inputTime = mTimestampGenerator.GenerateInputTime(ioNumberDataPackets, mInputFormat.mSampleRate);
|
||||
err = input->PullInput(actionFlags, inputTime, mHostBus, ioNumberDataPackets);
|
||||
if (!err) {
|
||||
input->CopyBufferListTo(ioData);
|
||||
if (!(actionFlags & kAudioUnitRenderAction_OutputIsSilence))
|
||||
mSilentOutput = false;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
protected:
|
||||
/*! @var mHost */
|
||||
AUBase * mHost;
|
||||
/*! @var mHostBus */
|
||||
int mHostBus;
|
||||
|
||||
AUTimestampGenerator mTimestampGenerator;
|
||||
bool mIsPCMToPCM;
|
||||
bool mHasSRC;
|
||||
bool mSilentOutput;
|
||||
UInt32 mPreviousSilentFrames;
|
||||
};
|
||||
|
||||
#endif // __AUInputFormatConverter_h__
|
||||
|
|
@ -1,495 +0,0 @@
|
|||
/*
|
||||
File: AUMIDIBase.cpp
|
||||
Abstract: AUMIDIBase.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "AUMIDIBase.h"
|
||||
#include <CoreMIDI/CoreMIDI.h>
|
||||
#include "CAXException.h"
|
||||
|
||||
//temporary location
|
||||
enum
|
||||
{
|
||||
kMidiMessage_NoteOff = 0x80,
|
||||
kMidiMessage_NoteOn = 0x90,
|
||||
kMidiMessage_PolyPressure = 0xA0,
|
||||
kMidiMessage_ControlChange = 0xB0,
|
||||
kMidiMessage_ProgramChange = 0xC0,
|
||||
kMidiMessage_ChannelPressure = 0xD0,
|
||||
kMidiMessage_PitchWheel = 0xE0,
|
||||
|
||||
kMidiController_AllSoundOff = 120,
|
||||
kMidiController_ResetAllControllers = 121,
|
||||
kMidiController_AllNotesOff = 123
|
||||
};
|
||||
|
||||
AUMIDIBase::AUMIDIBase(AUBase* inBase)
|
||||
: mAUBaseInstance (*inBase)
|
||||
{
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
mMapManager = new CAAUMIDIMapManager();
|
||||
#endif
|
||||
}
|
||||
|
||||
AUMIDIBase::~AUMIDIBase()
|
||||
{
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
if (mMapManager)
|
||||
delete mMapManager;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TARGET_API_MAC_OSX
|
||||
OSStatus AUMIDIBase::DelegateGetPropertyInfo(AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 & outDataSize,
|
||||
Boolean & outWritable)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
switch (inID) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
case kMusicDeviceProperty_MIDIXMLNames:
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
if (GetXMLNames(NULL) == noErr) {
|
||||
outDataSize = sizeof(CFURLRef);
|
||||
outWritable = false;
|
||||
} else
|
||||
result = kAudioUnitErr_InvalidProperty;
|
||||
break;
|
||||
#endif
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
case kAudioUnitProperty_AllParameterMIDIMappings:
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
outWritable = true;
|
||||
outDataSize = sizeof (AUParameterMIDIMapping)*mMapManager->NumMaps();
|
||||
result = noErr;
|
||||
break;
|
||||
|
||||
case kAudioUnitProperty_HotMapParameterMIDIMapping:
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
outWritable = true;
|
||||
outDataSize = sizeof (AUParameterMIDIMapping);
|
||||
result = noErr;
|
||||
break;
|
||||
|
||||
case kAudioUnitProperty_AddParameterMIDIMapping:
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
outWritable = true;
|
||||
outDataSize = sizeof (AUParameterMIDIMapping);
|
||||
result = noErr;
|
||||
break;
|
||||
|
||||
case kAudioUnitProperty_RemoveParameterMIDIMapping:
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
outWritable = true;
|
||||
outDataSize = sizeof (AUParameterMIDIMapping);
|
||||
result = noErr;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
result = kAudioUnitErr_InvalidProperty;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
#if CA_AUTO_MIDI_MAP || (!TARGET_OS_IPHONE)
|
||||
InvalidScope:
|
||||
return kAudioUnitErr_InvalidScope;
|
||||
InvalidElement:
|
||||
return kAudioUnitErr_InvalidElement;
|
||||
#endif
|
||||
}
|
||||
|
||||
OSStatus AUMIDIBase::DelegateGetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
void * outData)
|
||||
{
|
||||
OSStatus result;
|
||||
|
||||
switch (inID) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
case kMusicDeviceProperty_MIDIXMLNames:
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
result = GetXMLNames((CFURLRef *)outData);
|
||||
break;
|
||||
#endif
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
case kAudioUnitProperty_AllParameterMIDIMappings:{
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
AUParameterMIDIMapping* maps = (static_cast<AUParameterMIDIMapping*>(outData));
|
||||
mMapManager->GetMaps(maps);
|
||||
// printf ("GETTING MAPS\n");
|
||||
// mMapManager->Print();
|
||||
result = noErr;
|
||||
break;
|
||||
}
|
||||
|
||||
case kAudioUnitProperty_HotMapParameterMIDIMapping:{
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
AUParameterMIDIMapping * map = (static_cast<AUParameterMIDIMapping*>(outData));
|
||||
mMapManager->GetHotParameterMap (*map);
|
||||
result = noErr;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
result = kAudioUnitErr_InvalidProperty;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
#if CA_AUTO_MIDI_MAP || (!TARGET_OS_IPHONE)
|
||||
InvalidScope:
|
||||
return kAudioUnitErr_InvalidScope;
|
||||
InvalidElement:
|
||||
return kAudioUnitErr_InvalidElement;
|
||||
#endif
|
||||
}
|
||||
|
||||
OSStatus AUMIDIBase::DelegateSetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
const void * inData,
|
||||
UInt32 inDataSize)
|
||||
{
|
||||
OSStatus result;
|
||||
|
||||
switch (inID) {
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
case kAudioUnitProperty_AddParameterMIDIMapping:{
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData;
|
||||
mMapManager->SortedInsertToParamaterMaps (maps, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance);
|
||||
mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);
|
||||
result = noErr;
|
||||
break;
|
||||
}
|
||||
|
||||
case kAudioUnitProperty_RemoveParameterMIDIMapping:{
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData;
|
||||
bool didChange;
|
||||
mMapManager->SortedRemoveFromParameterMaps(maps, (inDataSize / sizeof(AUParameterMIDIMapping)), didChange);
|
||||
if (didChange)
|
||||
mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0);
|
||||
result = noErr;
|
||||
break;
|
||||
}
|
||||
|
||||
case kAudioUnitProperty_HotMapParameterMIDIMapping:{
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
AUParameterMIDIMapping & map = *((AUParameterMIDIMapping*)inData);
|
||||
mMapManager->SetHotMapping (map);
|
||||
result = noErr;
|
||||
break;
|
||||
}
|
||||
case kAudioUnitProperty_AllParameterMIDIMappings:{
|
||||
ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
|
||||
ca_require(inElement == 0, InvalidElement);
|
||||
AUParameterMIDIMapping * mappings = (AUParameterMIDIMapping*)inData;
|
||||
mMapManager->ReplaceAllMaps (mappings, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance);
|
||||
result = noErr;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
result = kAudioUnitErr_InvalidProperty;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
InvalidScope:
|
||||
return kAudioUnitErr_InvalidScope;
|
||||
InvalidElement:
|
||||
return kAudioUnitErr_InvalidElement;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //TARGET_API_MAC_OSX
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#pragma mark ____MidiDispatch
|
||||
|
||||
|
||||
inline const Byte * NextMIDIEvent(const Byte *event, const Byte *end)
|
||||
{
|
||||
Byte c = *event;
|
||||
switch (c >> 4) {
|
||||
default: // data byte -- assume in sysex
|
||||
while ((*++event & 0x80) == 0 && event < end)
|
||||
;
|
||||
break;
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
case 0xA:
|
||||
case 0xB:
|
||||
case 0xE:
|
||||
event += 3;
|
||||
break;
|
||||
case 0xC:
|
||||
case 0xD:
|
||||
event += 2;
|
||||
break;
|
||||
case 0xF:
|
||||
switch (c) {
|
||||
case 0xF0:
|
||||
while ((*++event & 0x80) == 0 && event < end)
|
||||
;
|
||||
break;
|
||||
case 0xF1:
|
||||
case 0xF3:
|
||||
event += 2;
|
||||
break;
|
||||
case 0xF2:
|
||||
event += 3;
|
||||
break;
|
||||
default:
|
||||
++event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (event >= end) ? end : event;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUMIDIBase::HandleMIDIPacketList
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
OSStatus AUMIDIBase::HandleMIDIPacketList(const MIDIPacketList *pktlist)
|
||||
{
|
||||
if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
|
||||
|
||||
int nPackets = pktlist->numPackets;
|
||||
const MIDIPacket *pkt = pktlist->packet;
|
||||
|
||||
while (nPackets-- > 0) {
|
||||
const Byte *event = pkt->data, *packetEnd = event + pkt->length;
|
||||
long startFrame = (long)pkt->timeStamp;
|
||||
while (event < packetEnd) {
|
||||
Byte status = event[0];
|
||||
if (status & 0x80) {
|
||||
// really a status byte (not sysex continuation)
|
||||
HandleMidiEvent(status & 0xF0, status & 0x0F, event[1], event[2], static_cast<UInt32>(startFrame));
|
||||
// note that we're generating a bogus channel number for system messages (0xF0-FF)
|
||||
}
|
||||
event = NextMIDIEvent(event, packetEnd);
|
||||
}
|
||||
pkt = reinterpret_cast<const MIDIPacket *>(packetEnd);
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUMIDIBase::HandleMidiEvent
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
OSStatus AUMIDIBase::HandleMidiEvent(UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame)
|
||||
{
|
||||
if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
|
||||
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
// you potentially have a choice to make here - if a param mapping matches, do you still want to process the
|
||||
// MIDI event or not. The default behaviour is to continue on with the MIDI event.
|
||||
if (mMapManager->HandleHotMapping (status, channel, data1, mAUBaseInstance)) {
|
||||
mAUBaseInstance.PropertyChanged (kAudioUnitProperty_HotMapParameterMIDIMapping, kAudioUnitScope_Global, 0);
|
||||
}
|
||||
else {
|
||||
mMapManager->FindParameterMapEventMatch(status, channel, data1, data2, inStartFrame, mAUBaseInstance);
|
||||
}
|
||||
#endif
|
||||
|
||||
OSStatus result = noErr;
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case kMidiMessage_NoteOn:
|
||||
if(data2)
|
||||
{
|
||||
result = HandleNoteOn(channel, data1, data2, inStartFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
// zero velocity translates to note off
|
||||
result = HandleNoteOff(channel, data1, data2, inStartFrame);
|
||||
}
|
||||
break;
|
||||
|
||||
case kMidiMessage_NoteOff:
|
||||
result = HandleNoteOff(channel, data1, data2, inStartFrame);
|
||||
break;
|
||||
|
||||
default:
|
||||
result = HandleNonNoteEvent (status, channel, data1, data2, inStartFrame);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus AUMIDIBase::HandleNonNoteEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case kMidiMessage_PitchWheel:
|
||||
result = HandlePitchWheel(channel, data1, data2, inStartFrame);
|
||||
break;
|
||||
|
||||
case kMidiMessage_ProgramChange:
|
||||
result = HandleProgramChange(channel, data1);
|
||||
break;
|
||||
|
||||
case kMidiMessage_ChannelPressure:
|
||||
result = HandleChannelPressure(channel, data1, inStartFrame);
|
||||
break;
|
||||
|
||||
case kMidiMessage_ControlChange:
|
||||
{
|
||||
switch (data1) {
|
||||
case kMidiController_AllNotesOff:
|
||||
result = HandleAllNotesOff(channel);
|
||||
break;
|
||||
|
||||
case kMidiController_ResetAllControllers:
|
||||
result = HandleResetAllControllers(channel);
|
||||
break;
|
||||
|
||||
case kMidiController_AllSoundOff:
|
||||
result = HandleAllSoundOff(channel);
|
||||
break;
|
||||
|
||||
default:
|
||||
result = HandleControlChange(channel, data1, data2, inStartFrame);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kMidiMessage_PolyPressure:
|
||||
result = HandlePolyPressure (channel, data1, data2, inStartFrame);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus AUMIDIBase::SysEx (const UInt8 * inData,
|
||||
UInt32 inLength)
|
||||
{
|
||||
if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized;
|
||||
|
||||
return HandleSysEx(inData, inLength );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#if __LP64__
|
||||
// comp instance, parameters in forward order
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_index + 1];
|
||||
#else
|
||||
// parameters in reverse order, then comp instance
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index];
|
||||
#endif
|
||||
#elif TARGET_OS_WIN32
|
||||
// (no comp instance), parameters in forward order
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_index];
|
||||
#endif
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
OSStatus AUMIDIBase::ComponentEntryDispatch( ComponentParameters * params,
|
||||
AUMIDIBase * This)
|
||||
{
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
|
||||
OSStatus result;
|
||||
|
||||
switch (params->what) {
|
||||
case kMusicDeviceMIDIEventSelect:
|
||||
{
|
||||
PARAM(UInt32, pbinStatus, 0, 4);
|
||||
PARAM(UInt32, pbinData1, 1, 4);
|
||||
PARAM(UInt32, pbinData2, 2, 4);
|
||||
PARAM(UInt32, pbinOffsetSampleFrame, 3, 4);
|
||||
result = This->MIDIEvent(pbinStatus, pbinData1, pbinData2, pbinOffsetSampleFrame);
|
||||
}
|
||||
break;
|
||||
case kMusicDeviceSysExSelect:
|
||||
{
|
||||
PARAM(const UInt8 *, pbinData, 0, 2);
|
||||
PARAM(UInt32, pbinLength, 1, 2);
|
||||
result = This->SysEx(pbinData, pbinLength);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = badComponentSelector;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
File: AUMIDIBase.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUMIDIBase_h__
|
||||
#define __AUMIDIBase_h__
|
||||
|
||||
#include "AUBase.h"
|
||||
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
#include "CAAUMIDIMapManager.h"
|
||||
#endif
|
||||
|
||||
struct MIDIPacketList;
|
||||
|
||||
// ________________________________________________________________________
|
||||
// MusicDeviceBase
|
||||
//
|
||||
/*! @class AUMIDIBase */
|
||||
class AUMIDIBase {
|
||||
public:
|
||||
// this is NOT a copy constructor!
|
||||
/*! @ctor AUMIDIBase */
|
||||
AUMIDIBase(AUBase* inBase);
|
||||
/*! @dtor ~AUMIDIBase */
|
||||
virtual ~AUMIDIBase();
|
||||
|
||||
/*! @method MIDIEvent */
|
||||
virtual OSStatus MIDIEvent( UInt32 inStatus,
|
||||
UInt32 inData1,
|
||||
UInt32 inData2,
|
||||
UInt32 inOffsetSampleFrame)
|
||||
{
|
||||
UInt32 strippedStatus = inStatus & 0xf0;
|
||||
UInt32 channel = inStatus & 0x0f;
|
||||
|
||||
return HandleMidiEvent(strippedStatus, channel, inData1, inData2, inOffsetSampleFrame);
|
||||
}
|
||||
|
||||
/*! @method HandleMIDIPacketList */
|
||||
OSStatus HandleMIDIPacketList(const MIDIPacketList *pktlist);
|
||||
|
||||
/*! @method SysEx */
|
||||
virtual OSStatus SysEx( const UInt8 * inData,
|
||||
UInt32 inLength);
|
||||
|
||||
#if TARGET_API_MAC_OSX
|
||||
/*! @method DelegateGetPropertyInfo */
|
||||
virtual OSStatus DelegateGetPropertyInfo(AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 & outDataSize,
|
||||
Boolean & outWritable);
|
||||
|
||||
/*! @method DelegateGetProperty */
|
||||
virtual OSStatus DelegateGetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
void * outData);
|
||||
|
||||
/*! @method DelegateSetProperty */
|
||||
virtual OSStatus DelegateSetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
const void * inData,
|
||||
UInt32 inDataSize);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// MIDI dispatch
|
||||
/*! @method HandleMidiEvent */
|
||||
virtual OSStatus HandleMidiEvent( UInt8 inStatus,
|
||||
UInt8 inChannel,
|
||||
UInt8 inData1,
|
||||
UInt8 inData2,
|
||||
UInt32 inStartFrame);
|
||||
|
||||
/*! @method HandleNonNoteEvent */
|
||||
virtual OSStatus HandleNonNoteEvent ( UInt8 status,
|
||||
UInt8 channel,
|
||||
UInt8 data1,
|
||||
UInt8 data2,
|
||||
UInt32 inStartFrame);
|
||||
|
||||
#if TARGET_API_MAC_OSX
|
||||
/*! @method GetXMLNames */
|
||||
virtual OSStatus GetXMLNames(CFURLRef *outNameDocument)
|
||||
{ return kAudioUnitErr_InvalidProperty; } // if not overridden, it's unsupported
|
||||
#endif
|
||||
|
||||
// channel messages
|
||||
/*! @method HandleNoteOn */
|
||||
virtual OSStatus HandleNoteOn( UInt8 inChannel,
|
||||
UInt8 inNoteNumber,
|
||||
UInt8 inVelocity,
|
||||
UInt32 inStartFrame) { return noErr; }
|
||||
|
||||
/*! @method HandleNoteOff */
|
||||
virtual OSStatus HandleNoteOff( UInt8 inChannel,
|
||||
UInt8 inNoteNumber,
|
||||
UInt8 inVelocity,
|
||||
UInt32 inStartFrame) { return noErr; }
|
||||
|
||||
/*! @method HandleControlChange */
|
||||
virtual OSStatus HandleControlChange( UInt8 inChannel,
|
||||
UInt8 inController,
|
||||
UInt8 inValue,
|
||||
UInt32 inStartFrame) { return noErr; }
|
||||
|
||||
/*! @method HandlePitchWheel */
|
||||
virtual OSStatus HandlePitchWheel( UInt8 inChannel,
|
||||
UInt8 inPitch1,
|
||||
UInt8 inPitch2,
|
||||
UInt32 inStartFrame) { return noErr; }
|
||||
|
||||
/*! @method HandleChannelPressure */
|
||||
virtual OSStatus HandleChannelPressure( UInt8 inChannel,
|
||||
UInt8 inValue,
|
||||
UInt32 inStartFrame) { return noErr; }
|
||||
|
||||
/*! @method HandleProgramChange */
|
||||
virtual OSStatus HandleProgramChange( UInt8 inChannel,
|
||||
UInt8 inValue) { return noErr; }
|
||||
|
||||
/*! @method HandlePolyPressure */
|
||||
virtual OSStatus HandlePolyPressure( UInt8 inChannel,
|
||||
UInt8 inKey,
|
||||
UInt8 inValue,
|
||||
UInt32 inStartFrame) { return noErr; }
|
||||
|
||||
/*! @method HandleResetAllControllers */
|
||||
virtual OSStatus HandleResetAllControllers(UInt8 inChannel) { return noErr; }
|
||||
|
||||
/*! @method HandleAllNotesOff */
|
||||
virtual OSStatus HandleAllNotesOff( UInt8 inChannel) { return noErr; }
|
||||
|
||||
/*! @method HandleAllSoundOff */
|
||||
virtual OSStatus HandleAllSoundOff( UInt8 inChannel) { return noErr; }
|
||||
|
||||
|
||||
//System messages
|
||||
/*! @method HandleSysEx */
|
||||
virtual OSStatus HandleSysEx( const UInt8 * inData,
|
||||
UInt32 inLength ) { return noErr; }
|
||||
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
/* map manager */
|
||||
CAAUMIDIMapManager *GetMIDIMapManager() {return mMapManager;};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
/*! @var mAUBaseInstance */
|
||||
AUBase & mAUBaseInstance;
|
||||
|
||||
#if CA_AUTO_MIDI_MAP
|
||||
/* map manager */
|
||||
CAAUMIDIMapManager * mMapManager;
|
||||
#endif
|
||||
|
||||
public:
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
// component dispatcher
|
||||
/*! @method ComponentEntryDispatch */
|
||||
static OSStatus ComponentEntryDispatch( ComponentParameters *params,
|
||||
AUMIDIBase *This);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // __AUMIDIBase_h__
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
File: AUOutputBase.cpp
|
||||
Abstract: AUOutputBase.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
#include "AUOutputBase.h"
|
||||
|
||||
OSStatus AUOutputBase::ComponentEntryDispatch(ComponentParameters *params, AUOutputBase *This)
|
||||
{
|
||||
if (This == NULL) return paramErr;
|
||||
|
||||
OSStatus result;
|
||||
|
||||
switch (params->what) {
|
||||
case kAudioOutputUnitStartSelect:
|
||||
{
|
||||
result = This->Start();
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioOutputUnitStopSelect:
|
||||
{
|
||||
result = This->Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = badComponentSelector;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
File: AUOutputBase.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUOutputBase_h__
|
||||
#define __AUOutputBase_h__
|
||||
|
||||
#include "AUBase.h"
|
||||
|
||||
// ________________________________________________________________________
|
||||
// AUOutputBase
|
||||
// this is now a mix-in rather than an AUBase subclass
|
||||
|
||||
/*! @class AUOutputBase */
|
||||
class AUOutputBase {
|
||||
public:
|
||||
/*! @ctor AUOutputBase */
|
||||
AUOutputBase(AUBase *inBase) : mAUBaseInstance(*inBase) { }
|
||||
virtual ~AUOutputBase() { }
|
||||
|
||||
// additional component entry points
|
||||
/*! @method Start */
|
||||
virtual OSStatus Start() = 0;
|
||||
|
||||
/*! @method Stop */
|
||||
virtual OSStatus Stop() = 0;
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
// component dispatcher
|
||||
/*! @method ComponentEntryDispatch */
|
||||
static OSStatus ComponentEntryDispatch( ComponentParameters * params,
|
||||
AUOutputBase * This);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/*! @var mAUBaseInstance */
|
||||
AUBase & mAUBaseInstance;
|
||||
};
|
||||
|
||||
#endif // __AUOutputBase_h__
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
File: AUOutputElement.cpp
|
||||
Abstract: AUOutputElement.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "AUOutputElement.h"
|
||||
#include "AUBase.h"
|
||||
|
||||
AUOutputElement::AUOutputElement(AUBase *audioUnit) :
|
||||
AUIOElement(audioUnit)
|
||||
{
|
||||
AllocateBuffer();
|
||||
}
|
||||
|
||||
OSStatus AUOutputElement::SetStreamFormat(const CAStreamBasicDescription &desc)
|
||||
{
|
||||
OSStatus result = AUIOElement::SetStreamFormat(desc); // inherited
|
||||
if (result == AUBase::noErr)
|
||||
AllocateBuffer();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
File: AUOutputElement.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUOutput_h__
|
||||
#define __AUOutput_h__
|
||||
|
||||
#include "AUScopeElement.h"
|
||||
#include "AUBuffer.h"
|
||||
|
||||
/*! @class AUOutputElement */
|
||||
class AUOutputElement : public AUIOElement {
|
||||
public:
|
||||
/*! @ctor AUOutputElement */
|
||||
AUOutputElement(AUBase *audioUnit);
|
||||
|
||||
// AUElement override
|
||||
/*! @method SetStreamFormat */
|
||||
virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
|
||||
/*! @method NeedsBufferSpace */
|
||||
virtual bool NeedsBufferSpace() const { return true; }
|
||||
};
|
||||
|
||||
#endif // __AUOutput_h__
|
||||
|
|
@ -1,668 +0,0 @@
|
|||
/*
|
||||
File: AUPlugInDispatch.cpp
|
||||
Abstract: AUPlugInDispatch.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "AUPlugInDispatch.h"
|
||||
#include "CAXException.h"
|
||||
#include "ComponentBase.h"
|
||||
#include "AUBase.h"
|
||||
|
||||
#define ACPI ((AudioComponentPlugInInstance *)self)
|
||||
#define AUI ((AUBase *)&ACPI->mInstanceStorage)
|
||||
|
||||
#define AUI_LOCK CAMutex::Locker auLock(AUI->GetMutex());
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static OSStatus AUMethodInitialize(void *self)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->DoInitialize();
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodUninitialize(void *self)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
AUI->DoCleanup();
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodGetPropertyInfo(void *self, AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, UInt32 *outDataSize, Boolean *outWritable)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
UInt32 dataSize = 0; // 13517289 GetPropetyInfo was returning an uninitialized value when there is an error. This is a problem for auval.
|
||||
Boolean writable = false;
|
||||
|
||||
AUI_LOCK
|
||||
result = AUI->DispatchGetPropertyInfo(prop, scope, elem, dataSize, writable);
|
||||
if (outDataSize != NULL)
|
||||
*outDataSize = dataSize;
|
||||
if (outWritable != NULL)
|
||||
*outWritable = writable;
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodGetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void *outData, UInt32 *ioDataSize)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
UInt32 actualPropertySize, clientBufferSize;
|
||||
Boolean writable;
|
||||
char *tempBuffer;
|
||||
void *destBuffer;
|
||||
|
||||
AUI_LOCK
|
||||
if (ioDataSize == NULL) {
|
||||
ca_debug_string("AudioUnitGetProperty: null size pointer");
|
||||
result = kAudio_ParamError;
|
||||
goto finishGetProperty;
|
||||
}
|
||||
if (outData == NULL) {
|
||||
UInt32 dataSize;
|
||||
|
||||
result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, dataSize, writable);
|
||||
*ioDataSize = dataSize;
|
||||
goto finishGetProperty;
|
||||
}
|
||||
|
||||
clientBufferSize = *ioDataSize;
|
||||
if (clientBufferSize == 0)
|
||||
{
|
||||
ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry");
|
||||
// $$$ or should we allow this as a shortcut for finding the size?
|
||||
result = kAudio_ParamError;
|
||||
goto finishGetProperty;
|
||||
}
|
||||
|
||||
result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, actualPropertySize, writable);
|
||||
if (result != noErr)
|
||||
goto finishGetProperty;
|
||||
|
||||
if (clientBufferSize < actualPropertySize)
|
||||
{
|
||||
tempBuffer = new char[actualPropertySize];
|
||||
destBuffer = tempBuffer;
|
||||
} else {
|
||||
tempBuffer = NULL;
|
||||
destBuffer = outData;
|
||||
}
|
||||
|
||||
result = AUI->DispatchGetProperty(inID, inScope, inElement, destBuffer);
|
||||
|
||||
if (result == noErr) {
|
||||
if (clientBufferSize < actualPropertySize && tempBuffer != NULL)
|
||||
{
|
||||
memcpy(outData, tempBuffer, clientBufferSize);
|
||||
delete[] tempBuffer;
|
||||
// ioDataSize remains correct, the number of bytes we wrote
|
||||
} else
|
||||
*ioDataSize = actualPropertySize;
|
||||
} else
|
||||
*ioDataSize = 0;
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
finishGetProperty:
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodSetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void *inData, UInt32 inDataSize)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
if (inData && inDataSize)
|
||||
result = AUI->DispatchSetProperty(inID, inScope, inElement, inData, inDataSize);
|
||||
else {
|
||||
if (inData == NULL && inDataSize == 0) {
|
||||
result = AUI->DispatchRemovePropertyValue(inID, inScope, inElement);
|
||||
} else {
|
||||
if (inData == NULL) {
|
||||
ca_debug_string("AudioUnitSetProperty: inData == NULL");
|
||||
result = kAudio_ParamError;
|
||||
goto finishSetProperty;
|
||||
}
|
||||
|
||||
if (inDataSize == 0) {
|
||||
ca_debug_string("AudioUnitSetProperty: inDataSize == 0");
|
||||
result = kAudio_ParamError;
|
||||
goto finishSetProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
finishSetProperty:
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodAddPropertyListener(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void *userData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->AddPropertyListener(prop, proc, userData);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodRemovePropertyListener(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->RemovePropertyListener(prop, proc, NULL, false);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodRemovePropertyListenerWithUserData(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void *userData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->RemovePropertyListener(prop, proc, userData, true);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodAddRenderNotify(void *self, AURenderCallback proc, void *userData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->SetRenderNotification(proc, userData);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodRemoveRenderNotify(void *self, AURenderCallback proc, void *userData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->RemoveRenderNotification(proc, userData);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodGetParameter(void *self, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement elem, AudioUnitParameterValue *value)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = (value == NULL ? kAudio_ParamError : AUI->GetParameter(param, scope, elem, *value));
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodSetParameter(void *self, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement elem, AudioUnitParameterValue value, UInt32 bufferOffset)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a (potentially) realtime method; no lock
|
||||
result = AUI->SetParameter(param, scope, elem, value, bufferOffset);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodScheduleParameters(void *self, const AudioUnitParameterEvent *events, UInt32 numEvents)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a (potentially) realtime method; no lock
|
||||
result = AUI->ScheduleParameter(events, numEvents);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodRender(void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
try {
|
||||
#endif
|
||||
// this is a processing method; no lock
|
||||
AudioUnitRenderActionFlags tempFlags;
|
||||
|
||||
if (inTimeStamp == NULL || ioData == NULL)
|
||||
result = kAudio_ParamError;
|
||||
else {
|
||||
if (ioActionFlags == NULL) {
|
||||
tempFlags = 0;
|
||||
ioActionFlags = &tempFlags;
|
||||
}
|
||||
result = AUI->DoRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberFrames, *ioData);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodComplexRender(void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberOfPackets, UInt32 *outNumberOfPackets, AudioStreamPacketDescription *outPacketDescriptions, AudioBufferList *ioData, void *outMetadata, UInt32 *outMetadataByteSize)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
try {
|
||||
#endif
|
||||
// this is a processing method; no lock
|
||||
AudioUnitRenderActionFlags tempFlags;
|
||||
|
||||
if (inTimeStamp == NULL || ioData == NULL)
|
||||
result = kAudio_ParamError;
|
||||
else {
|
||||
if (ioActionFlags == NULL) {
|
||||
tempFlags = 0;
|
||||
ioActionFlags = &tempFlags;
|
||||
}
|
||||
result = AUI->ComplexRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberOfPackets, outNumberOfPackets, outPacketDescriptions, *ioData, outMetadata, outMetadataByteSize);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodReset(void *self, AudioUnitScope scope, AudioUnitElement elem)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->Reset(scope, elem);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodProcess (void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
try {
|
||||
#endif
|
||||
// this is a processing method; no lock
|
||||
bool doParamCheck = true;
|
||||
|
||||
AudioUnitRenderActionFlags tempFlags;
|
||||
|
||||
if (ioActionFlags == NULL) {
|
||||
tempFlags = 0;
|
||||
ioActionFlags = &tempFlags;
|
||||
} else {
|
||||
if (*ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)
|
||||
doParamCheck = false;
|
||||
}
|
||||
|
||||
if (doParamCheck && (inTimeStamp == NULL || ioData == NULL))
|
||||
result = kAudio_ParamError;
|
||||
else {
|
||||
result = AUI->DoProcess(*ioActionFlags, *inTimeStamp, inNumberFrames, *ioData);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodProcessMultiple (void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, UInt32 inNumberInputBufferLists, const AudioBufferList **inInputBufferLists, UInt32 inNumberOutputBufferLists, AudioBufferList **ioOutputBufferLists)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
try {
|
||||
#endif
|
||||
// this is a processing method; no lock
|
||||
bool doParamCheck = true;
|
||||
|
||||
AudioUnitRenderActionFlags tempFlags;
|
||||
|
||||
if (ioActionFlags == NULL) {
|
||||
tempFlags = 0;
|
||||
ioActionFlags = &tempFlags;
|
||||
} else {
|
||||
if (*ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)
|
||||
doParamCheck = false;
|
||||
}
|
||||
|
||||
if (doParamCheck && (inTimeStamp == NULL || inInputBufferLists == NULL || ioOutputBufferLists == NULL))
|
||||
result = kAudio_ParamError;
|
||||
else {
|
||||
result = AUI->DoProcessMultiple(*ioActionFlags, *inTimeStamp, inNumberFrames, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
static OSStatus AUMethodStart(void *self)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->Start();
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodStop(void *self)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
AUI_LOCK
|
||||
result = AUI->Stop();
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#if !CA_BASIC_AU_FEATURES
|
||||
// I don't know what I'm doing here; conflicts with the multiple inheritence in MusicDeviceBase.
|
||||
static OSStatus AUMethodMIDIEvent(void *self, UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a potential render-time method; no lock
|
||||
result = AUI->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodSysEx(void *self, const UInt8 *inData, UInt32 inLength)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a potential render-time method; no lock
|
||||
result = AUI->SysEx(inData, inLength);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodStartNote(void *self, MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a potential render-time method; no lock
|
||||
if (inParams == NULL || outNoteInstanceID == NULL)
|
||||
result = kAudio_ParamError;
|
||||
else
|
||||
result = AUI->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodStopNote(void *self, MusicDeviceGroupID inGroupID, NoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a potential render-time method; no lock
|
||||
result = AUI->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static OSStatus AUMethodPrepareInstrument (void *self, MusicDeviceInstrumentID inInstrument)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a potential render-time method; no lock
|
||||
result = AUI->PrepareInstrument(inInstrument);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
static OSStatus AUMethodReleaseInstrument (void *self, MusicDeviceInstrumentID inInstrument)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
// this is a potential render-time method; no lock
|
||||
result = AUI->ReleaseInstrument(inInstrument);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
#endif // TARGET_OS_IPHONE
|
||||
#endif // CA_BASIC_AU_FEATURES
|
||||
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
#pragma mark -
|
||||
#pragma mark Lookup Methods
|
||||
|
||||
AudioComponentMethod AUBaseLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
switch (selector) {
|
||||
case kAudioUnitInitializeSelect: return (AudioComponentMethod)AUMethodInitialize;
|
||||
case kAudioUnitUninitializeSelect: return (AudioComponentMethod)AUMethodUninitialize;
|
||||
case kAudioUnitGetPropertyInfoSelect: return (AudioComponentMethod)AUMethodGetPropertyInfo;
|
||||
case kAudioUnitGetPropertySelect: return (AudioComponentMethod)AUMethodGetProperty;
|
||||
case kAudioUnitSetPropertySelect: return (AudioComponentMethod)AUMethodSetProperty;
|
||||
case kAudioUnitAddPropertyListenerSelect:return (AudioComponentMethod)AUMethodAddPropertyListener;
|
||||
case kAudioUnitRemovePropertyListenerSelect:
|
||||
return (AudioComponentMethod)AUMethodRemovePropertyListener;
|
||||
case kAudioUnitRemovePropertyListenerWithUserDataSelect:
|
||||
return (AudioComponentMethod)AUMethodRemovePropertyListenerWithUserData;
|
||||
case kAudioUnitAddRenderNotifySelect: return (AudioComponentMethod)AUMethodAddRenderNotify;
|
||||
case kAudioUnitRemoveRenderNotifySelect:return (AudioComponentMethod)AUMethodRemoveRenderNotify;
|
||||
case kAudioUnitGetParameterSelect: return (AudioComponentMethod)AUMethodGetParameter;
|
||||
case kAudioUnitSetParameterSelect: return (AudioComponentMethod)AUMethodSetParameter;
|
||||
case kAudioUnitScheduleParametersSelect:return (AudioComponentMethod)AUMethodScheduleParameters;
|
||||
case kAudioUnitRenderSelect: return (AudioComponentMethod)AUMethodRender;
|
||||
case kAudioUnitResetSelect: return (AudioComponentMethod)AUMethodReset;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioComponentMethod AUOutputLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
switch (selector) {
|
||||
case kAudioOutputUnitStartSelect: return (AudioComponentMethod)AUMethodStart;
|
||||
case kAudioOutputUnitStopSelect: return (AudioComponentMethod)AUMethodStop;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioComponentMethod AUComplexOutputLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
method = AUOutputLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
if (selector == kAudioUnitComplexRenderSelect)
|
||||
return (AudioComponentMethod)AUMethodComplexRender;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioComponentMethod AUBaseProcessLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
if (selector == kAudioUnitProcessSelect)
|
||||
return (AudioComponentMethod)AUMethodProcess;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioComponentMethod AUBaseProcessMultipleLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
if (selector == kAudioUnitProcessMultipleSelect)
|
||||
return (AudioComponentMethod)AUMethodProcessMultiple;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioComponentMethod AUBaseProcessAndMultipleLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
method = AUBaseProcessMultipleLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
method = AUBaseProcessLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !CA_BASIC_AU_FEATURES
|
||||
inline AudioComponentMethod MIDI_Lookup (SInt16 selector)
|
||||
{
|
||||
switch (selector) {
|
||||
case kMusicDeviceMIDIEventSelect: return (AudioComponentMethod)AUMethodMIDIEvent;
|
||||
case kMusicDeviceSysExSelect: return (AudioComponentMethod)AUMethodSysEx;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioComponentMethod AUMIDILookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
return MIDI_Lookup(selector);
|
||||
}
|
||||
|
||||
AudioComponentMethod AUMIDIProcessLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseProcessLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
return MIDI_Lookup(selector);
|
||||
}
|
||||
|
||||
AudioComponentMethod AUMusicLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
AudioComponentMethod method = AUBaseLookup::Lookup(selector);
|
||||
if (method) return method;
|
||||
|
||||
switch (selector) {
|
||||
case kMusicDeviceStartNoteSelect: return (AudioComponentMethod)AUMethodStartNote;
|
||||
case kMusicDeviceStopNoteSelect: return (AudioComponentMethod)AUMethodStopNote;
|
||||
#if !TARGET_OS_IPHONE
|
||||
case kMusicDevicePrepareInstrumentSelect: return (AudioComponentMethod)AUMethodPrepareInstrument;
|
||||
case kMusicDeviceReleaseInstrumentSelect: return (AudioComponentMethod)AUMethodReleaseInstrument;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return MIDI_Lookup (selector);
|
||||
}
|
||||
|
||||
AudioComponentMethod AUAuxBaseLookup::Lookup (SInt16 selector)
|
||||
{
|
||||
switch (selector) {
|
||||
case kAudioUnitGetPropertyInfoSelect: return (AudioComponentMethod)AUMethodGetPropertyInfo;
|
||||
case kAudioUnitGetPropertySelect: return (AudioComponentMethod)AUMethodGetProperty;
|
||||
case kAudioUnitSetPropertySelect: return (AudioComponentMethod)AUMethodSetProperty;
|
||||
|
||||
case kAudioUnitGetParameterSelect: return (AudioComponentMethod)AUMethodGetParameter;
|
||||
case kAudioUnitSetParameterSelect: return (AudioComponentMethod)AUMethodSetParameter;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
File: AUPlugInDispatch.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUPlugInBase_h__
|
||||
#define __AUPlugInBase_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <AudioUnit/AudioComponent.h>
|
||||
#if !CA_BASIC_AU_FEATURES
|
||||
#include <AudioUnit/MusicDevice.h>
|
||||
#endif
|
||||
#else
|
||||
#include "AudioComponent.h"
|
||||
#include "MusicDevice.h"
|
||||
#endif
|
||||
|
||||
#include "ComponentBase.h"
|
||||
|
||||
struct AUBaseLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUBaseFactory : public APFactory<AUBaseLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUOutputLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUOutputBaseFactory : public APFactory<AUOutputLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUComplexOutputLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUOutputComplexBaseFactory : public APFactory<AUComplexOutputLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUBaseProcessLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUBaseProcessFactory : public APFactory<AUBaseProcessLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUBaseProcessMultipleLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUBaseProcessMultipleFactory : public APFactory<AUBaseProcessMultipleLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUBaseProcessAndMultipleLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUBaseProcessAndMultipleFactory : public APFactory<AUBaseProcessAndMultipleLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
#if !CA_BASIC_AU_FEATURES
|
||||
struct AUMIDILookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUMIDIEffectFactory : public APFactory<AUMIDILookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUMIDIProcessLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUMIDIProcessFactory : public APFactory<AUMIDIProcessLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUMusicLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUMusicDeviceFactory : public APFactory<AUMusicLookup, Implementor>
|
||||
{
|
||||
};
|
||||
|
||||
struct AUAuxBaseLookup {
|
||||
static AudioComponentMethod Lookup (SInt16 selector);
|
||||
};
|
||||
template <class Implementor>
|
||||
class AUAuxBaseFactory : public APFactory<AUAuxBaseLookup, Implementor>
|
||||
{
|
||||
};
|
||||
#endif // CA_BASIC_AU_FEATURES
|
||||
|
||||
#endif // __AUPlugInBase_h__
|
||||
|
|
@ -1,566 +0,0 @@
|
|||
/*
|
||||
File: AUScopeElement.cpp
|
||||
Abstract: AUScopeElement.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "AUScopeElement.h"
|
||||
#include "AUBase.h"
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
// By default, parameterIDs may be arbitrarily spaced, and an STL map
|
||||
// will be used for access. Calling UseIndexedParameters() will
|
||||
// instead use an STL vector for faster indexed access.
|
||||
// This assumes the paramIDs are numbered 0.....inNumberOfParameters-1
|
||||
// Call this before defining/adding any parameters with SetParameter()
|
||||
//
|
||||
void AUElement::UseIndexedParameters(int inNumberOfParameters)
|
||||
{
|
||||
mIndexedParameters.resize (inNumberOfParameters);
|
||||
mUseIndexedParameters = true;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
// Helper method.
|
||||
// returns the ParameterMapEvent object associated with the paramID
|
||||
//
|
||||
inline ParameterMapEvent& AUElement::GetParamEvent(AudioUnitParameterID paramID)
|
||||
{
|
||||
ParameterMapEvent *event;
|
||||
|
||||
if(mUseIndexedParameters)
|
||||
{
|
||||
if(paramID >= mIndexedParameters.size() )
|
||||
COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
|
||||
|
||||
event = &mIndexedParameters[paramID];
|
||||
}
|
||||
else
|
||||
{
|
||||
ParameterMap::iterator i = mParameters.find(paramID);
|
||||
if (i == mParameters.end())
|
||||
COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
|
||||
|
||||
event = &(*i).second;
|
||||
}
|
||||
|
||||
return *event;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
// Helper method.
|
||||
// returns whether the specified paramID is known to the element
|
||||
//
|
||||
bool AUElement::HasParameterID (AudioUnitParameterID paramID) const
|
||||
{
|
||||
if(mUseIndexedParameters)
|
||||
{
|
||||
if(paramID >= mIndexedParameters.size() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ParameterMap::const_iterator i = mParameters.find(paramID);
|
||||
if (i == mParameters.end())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
// caller assumes that this is actually an immediate parameter
|
||||
//
|
||||
AudioUnitParameterValue AUElement::GetParameter(AudioUnitParameterID paramID)
|
||||
{
|
||||
ParameterMapEvent &event = GetParamEvent(paramID);
|
||||
|
||||
return event.GetValue();
|
||||
}
|
||||
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUElement::GetRampSliceStartEnd( AudioUnitParameterID paramID,
|
||||
AudioUnitParameterValue & outStartValue,
|
||||
AudioUnitParameterValue & outEndValue,
|
||||
AudioUnitParameterValue & outValuePerFrameDelta )
|
||||
|
||||
{
|
||||
ParameterMapEvent &event = GetParamEvent(paramID);
|
||||
|
||||
// works even if the value is constant (immediate parameter value)
|
||||
event.GetRampSliceStartEnd(outStartValue, outEndValue, outValuePerFrameDelta );
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
AudioUnitParameterValue AUElement::GetEndValue( AudioUnitParameterID paramID)
|
||||
|
||||
{
|
||||
ParameterMapEvent &event = GetParamEvent(paramID);
|
||||
|
||||
// works even if the value is constant (immediate parameter value)
|
||||
return event.GetEndValue();
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUElement::SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue inValue, bool okWhenInitialized)
|
||||
{
|
||||
if(mUseIndexedParameters)
|
||||
{
|
||||
ParameterMapEvent &event = GetParamEvent(paramID);
|
||||
event.SetValue(inValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParameterMap::iterator i = mParameters.find(paramID);
|
||||
|
||||
if (i == mParameters.end())
|
||||
{
|
||||
if (mAudioUnit->IsInitialized() && !okWhenInitialized) {
|
||||
// The AU should not be creating new parameters once initialized.
|
||||
// If a client tries to set an undefined parameter, we could throw as follows,
|
||||
// but this might cause a regression. So it is better to just fail silently.
|
||||
// COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
|
||||
#if DEBUG
|
||||
fprintf(stderr, "WARNING: %s SetParameter for undefined param ID %d while initialized. Ignoring..\n",
|
||||
mAudioUnit->GetLoggingString(), (int)paramID);
|
||||
#endif
|
||||
} else {
|
||||
// create new entry in map for the paramID (only happens first time)
|
||||
ParameterMapEvent event(inValue);
|
||||
mParameters[paramID] = event;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// paramID already exists in map so simply change its value
|
||||
ParameterMapEvent &event = (*i).second;
|
||||
event.SetValue(inValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUElement::SetScheduledEvent( AudioUnitParameterID paramID,
|
||||
const AudioUnitParameterEvent &inEvent,
|
||||
UInt32 inSliceOffsetInBuffer,
|
||||
UInt32 inSliceDurationFrames,
|
||||
bool okWhenInitialized )
|
||||
{
|
||||
if(mUseIndexedParameters)
|
||||
{
|
||||
ParameterMapEvent &event = GetParamEvent(paramID);
|
||||
event.SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
|
||||
}
|
||||
else
|
||||
{
|
||||
ParameterMap::iterator i = mParameters.find(paramID);
|
||||
|
||||
if (i == mParameters.end())
|
||||
{
|
||||
if (mAudioUnit->IsInitialized() && !okWhenInitialized) {
|
||||
// The AU should not be creating new parameters once initialized.
|
||||
// If a client tries to set an undefined parameter, we could throw as follows,
|
||||
// but this might cause a regression. So it is better to just fail silently.
|
||||
// COMPONENT_THROW(kAudioUnitErr_InvalidParameter);
|
||||
#if DEBUG
|
||||
fprintf(stderr, "WARNING: %s SetScheduledEvent for undefined param ID %d while initialized. Ignoring..\n",
|
||||
mAudioUnit->GetLoggingString(), (int)paramID);
|
||||
#endif
|
||||
} else {
|
||||
// create new entry in map for the paramID (only happens first time)
|
||||
ParameterMapEvent event(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames);
|
||||
mParameters[paramID] = event;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// paramID already exists in map so simply change its value
|
||||
ParameterMapEvent &event = (*i).second;
|
||||
|
||||
event.SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUElement::GetParameterList(AudioUnitParameterID *outList)
|
||||
{
|
||||
if(mUseIndexedParameters)
|
||||
{
|
||||
UInt32 nparams = static_cast<UInt32>(mIndexedParameters.size());
|
||||
for (UInt32 i = 0; i < nparams; i++ )
|
||||
*outList++ = (AudioUnitParameterID)i;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ParameterMap::iterator i = mParameters.begin(); i != mParameters.end(); ++i)
|
||||
*outList++ = (*i).first;
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUElement::SaveState(CFMutableDataRef data)
|
||||
{
|
||||
if(mUseIndexedParameters)
|
||||
{
|
||||
UInt32 nparams = static_cast<UInt32>(mIndexedParameters.size());
|
||||
UInt32 theData = CFSwapInt32HostToBig(nparams);
|
||||
CFDataAppendBytes(data, (UInt8 *)&theData, sizeof(nparams));
|
||||
|
||||
for (UInt32 i = 0; i < nparams; i++)
|
||||
{
|
||||
struct {
|
||||
UInt32 paramID;
|
||||
//CFSwappedFloat32 value; crashes gcc3 PFE
|
||||
UInt32 value; // really a big-endian float
|
||||
} entry;
|
||||
|
||||
entry.paramID = CFSwapInt32HostToBig(i);
|
||||
|
||||
AudioUnitParameterValue v = mIndexedParameters[i].GetValue();
|
||||
entry.value = CFSwapInt32HostToBig(*(UInt32 *)&v );
|
||||
|
||||
CFDataAppendBytes(data, (UInt8 *)&entry, sizeof(entry));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 nparams = CFSwapInt32HostToBig(static_cast<uint32_t>(mParameters.size()));
|
||||
CFDataAppendBytes(data, (UInt8 *)&nparams, sizeof(nparams));
|
||||
|
||||
for (ParameterMap::iterator i = mParameters.begin(); i != mParameters.end(); ++i) {
|
||||
struct {
|
||||
UInt32 paramID;
|
||||
//CFSwappedFloat32 value; crashes gcc3 PFE
|
||||
UInt32 value; // really a big-endian float
|
||||
} entry;
|
||||
|
||||
entry.paramID = CFSwapInt32HostToBig((*i).first);
|
||||
|
||||
AudioUnitParameterValue v = (*i).second.GetValue();
|
||||
entry.value = CFSwapInt32HostToBig(*(UInt32 *)&v );
|
||||
|
||||
CFDataAppendBytes(data, (UInt8 *)&entry, sizeof(entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
const UInt8 * AUElement::RestoreState(const UInt8 *state)
|
||||
{
|
||||
union FloatInt32 { UInt32 i; AudioUnitParameterValue f; };
|
||||
const UInt8 *p = state;
|
||||
UInt32 nparams = CFSwapInt32BigToHost(*(UInt32 *)p);
|
||||
p += sizeof(UInt32);
|
||||
|
||||
for (UInt32 i = 0; i < nparams; ++i) {
|
||||
struct {
|
||||
AudioUnitParameterID paramID;
|
||||
AudioUnitParameterValue value;
|
||||
} entry;
|
||||
|
||||
entry.paramID = CFSwapInt32BigToHost(*(UInt32 *)p);
|
||||
p += sizeof(UInt32);
|
||||
FloatInt32 temp;
|
||||
temp.i = CFSwapInt32BigToHost(*(UInt32 *)p);
|
||||
entry.value = temp.f;
|
||||
p += sizeof(AudioUnitParameterValue);
|
||||
|
||||
SetParameter(entry.paramID, entry.value);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUElement::SetName (CFStringRef inName)
|
||||
{
|
||||
if (mElementName) CFRelease (mElementName);
|
||||
mElementName = inName;
|
||||
if (mElementName) CFRetain (mElementName);
|
||||
}
|
||||
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
AUIOElement::AUIOElement(AUBase *audioUnit) :
|
||||
AUElement(audioUnit),
|
||||
mWillAllocate (true)
|
||||
{
|
||||
mStreamFormat.SetAUCanonical(2, // stereo
|
||||
audioUnit->AudioUnitAPIVersion() == 1);
|
||||
// interleaved if API version 1, deinterleaved if version 2
|
||||
mStreamFormat.mSampleRate = kAUDefaultSampleRate;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
OSStatus AUIOElement::SetStreamFormat(const CAStreamBasicDescription &desc)
|
||||
{
|
||||
mStreamFormat = desc;
|
||||
return AUBase::noErr;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
// inFramesToAllocate == 0 implies the AudioUnit's max-frames-per-slice will be used
|
||||
void AUIOElement::AllocateBuffer(UInt32 inFramesToAllocate)
|
||||
{
|
||||
if (GetAudioUnit()->HasBegunInitializing())
|
||||
{
|
||||
UInt32 framesToAllocate = inFramesToAllocate > 0 ? inFramesToAllocate : GetAudioUnit()->GetMaxFramesPerSlice();
|
||||
|
||||
// printf ("will allocate: %d\n", (int)((mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0));
|
||||
|
||||
mIOBuffer.Allocate(mStreamFormat, (mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0);
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUIOElement::DeallocateBuffer()
|
||||
{
|
||||
mIOBuffer.Deallocate();
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
// AudioChannelLayout support
|
||||
|
||||
// outLayoutTagsPtr WILL be NULL if called to find out how many
|
||||
// layouts that Audio Unit will report
|
||||
// return 0 (ie. NO channel layouts) if the AU doesn't require channel layout knowledge
|
||||
UInt32 AUIOElement::GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// As the AudioChannelLayout can be a variable length structure
|
||||
// (though in most cases it won't be!!!)
|
||||
// The size of the ACL is always returned by the method
|
||||
// if outMapPtr is NOT-NULL, then AU should copy into this pointer (outMapPtr) the current ACL that it has in use.
|
||||
// the AU should also return whether the property is writable (that is the client can provide any arbitrary ACL that the audio unit will then honour)
|
||||
// or if the property is read only - which is the generally preferred mode.
|
||||
// If the AU doesn't require an AudioChannelLayout, then just return 0.
|
||||
UInt32 AUIOElement::GetAudioChannelLayout (AudioChannelLayout *outMapPtr,
|
||||
Boolean &outWritable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the incoming channel map will be at least as big as a basic AudioChannelLayout
|
||||
// but its contents will determine its actual size
|
||||
// Subclass should overide if channel map is writable
|
||||
OSStatus AUIOElement::SetAudioChannelLayout (const AudioChannelLayout &inData)
|
||||
{
|
||||
return kAudioUnitErr_InvalidProperty;
|
||||
}
|
||||
|
||||
// Some units support optional usage of channel maps - typically converter units
|
||||
// that can do channel remapping between different maps. In that optional case
|
||||
// the user should be able to remove a channel map if that is possible.
|
||||
// Typically this is NOT the case (e.g., the 3DMixer even in the stereo case
|
||||
// needs to know if it is rendering to speakers or headphones)
|
||||
OSStatus AUIOElement::RemoveAudioChannelLayout ()
|
||||
{
|
||||
return kAudioUnitErr_InvalidPropertyValue;
|
||||
}
|
||||
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
AUScope::~AUScope()
|
||||
{
|
||||
for (ElementVector::iterator it = mElements.begin(); it != mElements.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
void AUScope::SetNumberOfElements(UInt32 numElements)
|
||||
{
|
||||
if (mDelegate)
|
||||
return mDelegate->SetNumberOfElements(numElements);
|
||||
|
||||
if (numElements > mElements.size()) {
|
||||
mElements.reserve(numElements);
|
||||
while (numElements > mElements.size()) {
|
||||
AUElement *elem = mCreator->CreateElement(GetScope(), static_cast<UInt32>(mElements.size()));
|
||||
mElements.push_back(elem);
|
||||
}
|
||||
} else
|
||||
while (numElements < mElements.size()) {
|
||||
AUElement *elem = mElements.back();
|
||||
mElements.pop_back();
|
||||
delete elem;
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
bool AUScope::HasElementWithName () const
|
||||
{
|
||||
for (UInt32 i = 0; i < GetNumberOfElements(); ++i) {
|
||||
AUElement * el = const_cast<AUScope*>(this)->GetElement (i);
|
||||
if (el && el->HasName()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
|
||||
void AUScope::AddElementNamesToDict (CFMutableDictionaryRef & inNameDict)
|
||||
{
|
||||
if (HasElementWithName())
|
||||
{
|
||||
static char string[32];
|
||||
CFMutableDictionaryRef elementDict = CFDictionaryCreateMutable (NULL, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFStringRef str;
|
||||
for (UInt32 i = 0; i < GetNumberOfElements(); ++i) {
|
||||
AUElement * el = GetElement (i);
|
||||
if (el && el->HasName()) {
|
||||
snprintf (string, sizeof(string), "%d", int(i));
|
||||
str = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
|
||||
CFDictionarySetValue (elementDict, str, el->GetName());
|
||||
CFRelease (str);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf (string, sizeof(string), "%d", int(mScope));
|
||||
str = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
|
||||
CFDictionarySetValue (inNameDict, str, elementDict);
|
||||
CFRelease (str);
|
||||
CFRelease (elementDict);
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________
|
||||
//
|
||||
bool AUScope::RestoreElementNames (CFDictionaryRef& inNameDict)
|
||||
{
|
||||
static char string[32];
|
||||
|
||||
//first we have to see if we have enough elements
|
||||
bool didAddElements = false;
|
||||
unsigned int maxElNum = GetNumberOfElements();
|
||||
|
||||
int dictSize = static_cast<int>(CFDictionaryGetCount(inNameDict));
|
||||
CFStringRef * keys = (CFStringRef*)CA_malloc (dictSize * sizeof (CFStringRef));
|
||||
CFDictionaryGetKeysAndValues (inNameDict, reinterpret_cast<const void**>(keys), NULL);
|
||||
for (int i = 0; i < dictSize; i++)
|
||||
{
|
||||
unsigned int intKey = 0;
|
||||
CFStringGetCString (keys[i], string, 32, kCFStringEncodingASCII);
|
||||
int result = sscanf (string, "%u", &intKey);
|
||||
// check if sscanf succeeded and element index is less than max elements.
|
||||
if (result && UInt32(intKey) < maxElNum)
|
||||
{
|
||||
CFStringRef elName = reinterpret_cast<CFStringRef>(CFDictionaryGetValue (inNameDict, keys[i]));
|
||||
AUElement* element = GetElement (intKey);
|
||||
if (element)
|
||||
element->SetName (elName);
|
||||
}
|
||||
}
|
||||
free (keys);
|
||||
|
||||
return didAddElements;
|
||||
}
|
||||
|
||||
void AUScope::SaveState(CFMutableDataRef data)
|
||||
{
|
||||
AudioUnitElement nElems = GetNumberOfElements();
|
||||
for (AudioUnitElement ielem = 0; ielem < nElems; ++ielem) {
|
||||
AUElement *element = GetElement(ielem);
|
||||
UInt32 nparams = element->GetNumberOfParameters();
|
||||
if (nparams > 0) {
|
||||
struct {
|
||||
UInt32 scope;
|
||||
UInt32 element;
|
||||
} hdr;
|
||||
|
||||
hdr.scope = CFSwapInt32HostToBig(GetScope());
|
||||
hdr.element = CFSwapInt32HostToBig(ielem);
|
||||
CFDataAppendBytes(data, (UInt8 *)&hdr, sizeof(hdr));
|
||||
|
||||
element->SaveState(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const UInt8 * AUScope::RestoreState(const UInt8 *state)
|
||||
{
|
||||
const UInt8 *p = state;
|
||||
UInt32 elementIdx = CFSwapInt32BigToHost(*(UInt32 *)p); p += sizeof(UInt32);
|
||||
AUElement *element = GetElement(elementIdx);
|
||||
if (!element) {
|
||||
struct {
|
||||
AudioUnitParameterID paramID;
|
||||
AudioUnitParameterValue value;
|
||||
} entry;
|
||||
UInt32 nparams = CFSwapInt32BigToHost(*(UInt32 *)p);
|
||||
p += sizeof(UInt32);
|
||||
|
||||
p += nparams * sizeof(entry);
|
||||
} else
|
||||
p = element->RestoreState(p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
|
@ -1,553 +0,0 @@
|
|||
/*
|
||||
File: AUScopeElement.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUScopeElement_h__
|
||||
#define __AUScopeElement_h__
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#else
|
||||
#include <AudioUnit.h>
|
||||
#endif
|
||||
#include "ComponentBase.h"
|
||||
#include "AUBuffer.h"
|
||||
|
||||
|
||||
class AUBase;
|
||||
|
||||
// ____________________________________________________________________________
|
||||
//
|
||||
// represents a parameter's value (either constant or ramped)
|
||||
/*! @class ParameterMapEvent */
|
||||
class ParameterMapEvent
|
||||
{
|
||||
public:
|
||||
/*! @ctor ParameterMapEvent */
|
||||
ParameterMapEvent()
|
||||
: mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(0.0f), mValue2(0.0f), mSliceDurationFrames(0)
|
||||
{}
|
||||
|
||||
/*! @ctor ParameterMapEvent */
|
||||
ParameterMapEvent(AudioUnitParameterValue inValue)
|
||||
: mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(inValue), mValue2(inValue), mSliceDurationFrames(0)
|
||||
{}
|
||||
|
||||
// constructor for scheduled event
|
||||
/*! @ctor ParameterMapEvent */
|
||||
ParameterMapEvent( const AudioUnitParameterEvent &inEvent,
|
||||
UInt32 inSliceOffsetInBuffer,
|
||||
UInt32 inSliceDurationFrames )
|
||||
{
|
||||
SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames );
|
||||
};
|
||||
|
||||
/*! @method SetScheduledEvent */
|
||||
void SetScheduledEvent( const AudioUnitParameterEvent &inEvent,
|
||||
UInt32 inSliceOffsetInBuffer,
|
||||
UInt32 inSliceDurationFrames )
|
||||
{
|
||||
mEventType = inEvent.eventType;
|
||||
mSliceDurationFrames = inSliceDurationFrames;
|
||||
|
||||
if(mEventType == kParameterEvent_Immediate )
|
||||
{
|
||||
// constant immediate value for the whole slice
|
||||
mValue1 = inEvent.eventValues.immediate.value;
|
||||
mValue2 = mValue1;
|
||||
mDurationInFrames = inSliceDurationFrames;
|
||||
mBufferOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDurationInFrames = inEvent.eventValues.ramp.durationInFrames;
|
||||
mBufferOffset = inEvent.eventValues.ramp.startBufferOffset - inSliceOffsetInBuffer; // shift over for this slice
|
||||
mValue1 = inEvent.eventValues.ramp.startValue;
|
||||
mValue2 = inEvent.eventValues.ramp.endValue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*! @method GetEventType */
|
||||
AUParameterEventType GetEventType() const {return mEventType;};
|
||||
|
||||
/*! @method GetValue */
|
||||
AudioUnitParameterValue GetValue() const {return mValue1;}; // only valid if immediate event type
|
||||
/*! @method GetEndValue */
|
||||
AudioUnitParameterValue GetEndValue() const {return mValue2;}; // only valid if immediate event type
|
||||
/*! @method SetValue */
|
||||
void SetValue(AudioUnitParameterValue inValue)
|
||||
{
|
||||
mEventType = kParameterEvent_Immediate;
|
||||
mValue1 = inValue;
|
||||
mValue2 = inValue;
|
||||
}
|
||||
|
||||
// interpolates the start and end values corresponding to the current processing slice
|
||||
// most ramp parameter implementations will want to use this method
|
||||
// the start value will correspond to the start of the slice
|
||||
// the end value will correspond to the end of the slice
|
||||
/*! @method GetRampSliceStartEnd */
|
||||
void GetRampSliceStartEnd( AudioUnitParameterValue & outStartValue,
|
||||
AudioUnitParameterValue & outEndValue,
|
||||
AudioUnitParameterValue & outValuePerFrameDelta )
|
||||
{
|
||||
if (mEventType == kParameterEvent_Ramped) {
|
||||
outValuePerFrameDelta = (mValue2 - mValue1) / mDurationInFrames;
|
||||
|
||||
outStartValue = mValue1 + outValuePerFrameDelta * (-mBufferOffset); // corresponds to frame 0 of this slice
|
||||
outEndValue = outStartValue + outValuePerFrameDelta * mSliceDurationFrames;
|
||||
} else {
|
||||
outValuePerFrameDelta = 0;
|
||||
outStartValue = outEndValue = mValue1;
|
||||
}
|
||||
};
|
||||
|
||||
// Some ramp parameter implementations will want to interpret the ramp using their
|
||||
// own interpolation method (perhaps non-linear)
|
||||
// This method gives the raw ramp information, relative to this processing slice
|
||||
// for the client to interpret as desired
|
||||
/*! @method GetRampInfo */
|
||||
void GetRampInfo( SInt32 & outBufferOffset,
|
||||
UInt32 & outDurationInFrames,
|
||||
AudioUnitParameterValue & outStartValue,
|
||||
AudioUnitParameterValue & outEndValue )
|
||||
{
|
||||
outBufferOffset = mBufferOffset;
|
||||
outDurationInFrames = mDurationInFrames;
|
||||
outStartValue = mValue1;
|
||||
outEndValue = mValue2;
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
void Print()
|
||||
{
|
||||
printf("ParameterEvent @ %p\n", this);
|
||||
printf(" mEventType = %d\n", (int)mEventType);
|
||||
printf(" mBufferOffset = %d\n", (int)mBufferOffset);
|
||||
printf(" mDurationInFrames = %d\n", (int)mDurationInFrames);
|
||||
printf(" mSliceDurationFrames = %d\n", (int)mSliceDurationFrames);
|
||||
printf(" mValue1 = %.5f\n", mValue1);
|
||||
printf(" mValue2 = %.5f\n", mValue2);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
AUParameterEventType mEventType;
|
||||
|
||||
SInt32 mBufferOffset; // ramp start offset relative to start of this slice (may be negative)
|
||||
UInt32 mDurationInFrames; // total duration of ramp parameter
|
||||
AudioUnitParameterValue mValue1; // value if immediate : startValue if ramp
|
||||
AudioUnitParameterValue mValue2; // endValue (only used for ramp)
|
||||
|
||||
UInt32 mSliceDurationFrames; // duration of this processing slice
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ____________________________________________________________________________
|
||||
//
|
||||
class AUIOElement;
|
||||
|
||||
/*! @class AUElement */
|
||||
class AUElement {
|
||||
public:
|
||||
/*! @ctor AUElement */
|
||||
AUElement(AUBase *audioUnit) : mAudioUnit(audioUnit),
|
||||
mUseIndexedParameters(false), mElementName(0) { }
|
||||
|
||||
/*! @dtor ~AUElement */
|
||||
virtual ~AUElement() { if (mElementName) CFRelease (mElementName); }
|
||||
|
||||
/*! @method GetNumberOfParameters */
|
||||
virtual UInt32 GetNumberOfParameters()
|
||||
{
|
||||
if(mUseIndexedParameters) return static_cast<UInt32>(mIndexedParameters.size()); else return static_cast<UInt32>(mParameters.size());
|
||||
}
|
||||
/*! @method GetParameterList */
|
||||
virtual void GetParameterList(AudioUnitParameterID *outList);
|
||||
/*! @method HasParameterID */
|
||||
bool HasParameterID (AudioUnitParameterID paramID) const;
|
||||
|
||||
/*! @method GetParameter */
|
||||
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID);
|
||||
/*! @method SetParameter */
|
||||
void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value, bool okWhenInitialized = false);
|
||||
// Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted.
|
||||
|
||||
// interpolates the start and end values corresponding to the current processing slice
|
||||
// most ramp parameter implementations will want to use this method
|
||||
/*! @method GetRampSliceStartEnd */
|
||||
void GetRampSliceStartEnd( AudioUnitParameterID paramID,
|
||||
AudioUnitParameterValue & outStartValue,
|
||||
AudioUnitParameterValue & outEndValue,
|
||||
AudioUnitParameterValue & outValuePerFrameDelta );
|
||||
|
||||
/*! @method GetEndValue */
|
||||
AudioUnitParameterValue GetEndValue( AudioUnitParameterID paramID);
|
||||
|
||||
/*! @method SetRampParameter */
|
||||
void SetScheduledEvent( AudioUnitParameterID paramID,
|
||||
const AudioUnitParameterEvent &inEvent,
|
||||
UInt32 inSliceOffsetInBuffer,
|
||||
UInt32 inSliceDurationFrames,
|
||||
bool okWhenInitialized = false );
|
||||
// Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted.
|
||||
|
||||
|
||||
/*! @method GetAudioUnit */
|
||||
AUBase * GetAudioUnit() const { return mAudioUnit; };
|
||||
|
||||
/*! @method SaveState */
|
||||
void SaveState(CFMutableDataRef data);
|
||||
/*! @method RestoreState */
|
||||
const UInt8 * RestoreState(const UInt8 *state);
|
||||
/*! @method GetName */
|
||||
CFStringRef GetName () const { return mElementName; }
|
||||
/*! @method SetName */
|
||||
void SetName (CFStringRef inName);
|
||||
/*! @method HasName */
|
||||
bool HasName () const { return mElementName != 0; }
|
||||
/*! @method UseIndexedParameters */
|
||||
virtual void UseIndexedParameters(int inNumberOfParameters);
|
||||
|
||||
/*! @method AsIOElement*/
|
||||
virtual AUIOElement* AsIOElement () { return NULL; }
|
||||
|
||||
protected:
|
||||
inline ParameterMapEvent& GetParamEvent(AudioUnitParameterID paramID);
|
||||
|
||||
private:
|
||||
typedef std::map<AudioUnitParameterID, ParameterMapEvent, std::less<AudioUnitParameterID>> ParameterMap;
|
||||
|
||||
/*! @var mAudioUnit */
|
||||
AUBase * mAudioUnit;
|
||||
/*! @var mParameters */
|
||||
ParameterMap mParameters;
|
||||
|
||||
/*! @var mUseIndexedParameters */
|
||||
bool mUseIndexedParameters;
|
||||
/*! @var mIndexedParameters */
|
||||
std::vector<ParameterMapEvent> mIndexedParameters;
|
||||
|
||||
/*! @var mElementName */
|
||||
CFStringRef mElementName;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ____________________________________________________________________________
|
||||
//
|
||||
/*! @class AUIOElement */
|
||||
class AUIOElement : public AUElement {
|
||||
public:
|
||||
/*! @ctor AUIOElement */
|
||||
AUIOElement(AUBase *audioUnit);
|
||||
|
||||
/*! @method GetStreamFormat */
|
||||
const CAStreamBasicDescription &GetStreamFormat() const { return mStreamFormat; }
|
||||
|
||||
/*! @method SetStreamFormat */
|
||||
virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc);
|
||||
|
||||
/*! @method AllocateBuffer */
|
||||
virtual void AllocateBuffer(UInt32 inFramesToAllocate = 0);
|
||||
/*! @method DeallocateBuffer */
|
||||
void DeallocateBuffer();
|
||||
/*! @method NeedsBufferSpace */
|
||||
virtual bool NeedsBufferSpace() const = 0;
|
||||
|
||||
/*! @method SetWillAllocateBuffer */
|
||||
void SetWillAllocateBuffer(bool inFlag) {
|
||||
mWillAllocate = inFlag;
|
||||
}
|
||||
/*! @method WillAllocateBuffer */
|
||||
bool WillAllocateBuffer() const {
|
||||
return mWillAllocate;
|
||||
}
|
||||
|
||||
/*! @method UseExternalBuffer */
|
||||
void UseExternalBuffer(const AudioUnitExternalBuffer &buf) {
|
||||
mIOBuffer.UseExternalBuffer(mStreamFormat, buf);
|
||||
}
|
||||
/*! @method PrepareBuffer */
|
||||
AudioBufferList & PrepareBuffer(UInt32 nFrames) {
|
||||
if (mWillAllocate)
|
||||
return mIOBuffer.PrepareBuffer(mStreamFormat, nFrames);
|
||||
throw OSStatus(kAudioUnitErr_InvalidPropertyValue);
|
||||
}
|
||||
/*! @method PrepareNullBuffer */
|
||||
AudioBufferList & PrepareNullBuffer(UInt32 nFrames) {
|
||||
return mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames);
|
||||
}
|
||||
/*! @method SetBufferList */
|
||||
AudioBufferList & SetBufferList(AudioBufferList &abl) { return mIOBuffer.SetBufferList(abl); }
|
||||
/*! @method SetBuffer */
|
||||
void SetBuffer(UInt32 index, AudioBuffer &ab) { mIOBuffer.SetBuffer(index, ab); }
|
||||
/*! @method InvalidateBufferList */
|
||||
void InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); }
|
||||
|
||||
/*! @method GetBufferList */
|
||||
AudioBufferList & GetBufferList() const { return mIOBuffer.GetBufferList(); }
|
||||
|
||||
/*! @method GetChannelData */
|
||||
AudioUnitSampleType * GetChannelData(int ch) const {
|
||||
if (mStreamFormat.IsInterleaved())
|
||||
return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
|
||||
else
|
||||
return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
|
||||
}
|
||||
Float32 * GetFloat32ChannelData(int ch) const {
|
||||
if (mStreamFormat.IsInterleaved())
|
||||
return static_cast<Float32 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
|
||||
else
|
||||
return static_cast<Float32 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
|
||||
}
|
||||
SInt32 * GetSInt32ChannelData(int ch) const {
|
||||
if (mStreamFormat.IsInterleaved())
|
||||
return static_cast<SInt32 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
|
||||
else
|
||||
return static_cast<SInt32 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
|
||||
}
|
||||
SInt16 * GetInt16ChannelData(int ch) const {
|
||||
if (mStreamFormat.IsInterleaved())
|
||||
return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch;
|
||||
else
|
||||
return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData);
|
||||
}
|
||||
|
||||
/*! @method CopyBufferListTo */
|
||||
void CopyBufferListTo(AudioBufferList &abl) const {
|
||||
mIOBuffer.CopyBufferListTo(abl);
|
||||
}
|
||||
/*! @method CopyBufferContentsTo */
|
||||
void CopyBufferContentsTo(AudioBufferList &abl) const {
|
||||
mIOBuffer.CopyBufferContentsTo(abl);
|
||||
}
|
||||
|
||||
/* UInt32 BytesToFrames(UInt32 nBytes) { return nBytes / mStreamFormat.mBytesPerFrame; }
|
||||
UInt32 BytesToFrames(AudioBufferList &abl) {
|
||||
return BytesToFrames(abl.mBuffers[0].mDataByteSize);
|
||||
}
|
||||
UInt32 FramesToBytes(UInt32 nFrames) { return nFrames * mStreamFormat.mBytesPerFrame; }*/
|
||||
|
||||
/*! @method IsInterleaved */
|
||||
bool IsInterleaved() const { return mStreamFormat.IsInterleaved(); }
|
||||
/*! @method NumberChannels */
|
||||
UInt32 NumberChannels() const { return mStreamFormat.NumberChannels(); }
|
||||
/*! @method NumberInterleavedChannels */
|
||||
UInt32 NumberInterleavedChannels() const { return mStreamFormat.NumberInterleavedChannels(); }
|
||||
|
||||
/*! @method GetChannelMapTags */
|
||||
virtual UInt32 GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr);
|
||||
|
||||
/*! @method GetAudioChannelLayout */
|
||||
virtual UInt32 GetAudioChannelLayout (AudioChannelLayout *outMapPtr, Boolean &outWritable);
|
||||
|
||||
/*! @method SetAudioChannelLayout */
|
||||
virtual OSStatus SetAudioChannelLayout (const AudioChannelLayout &inData);
|
||||
|
||||
/*! @method RemoveAudioChannelLayout */
|
||||
virtual OSStatus RemoveAudioChannelLayout ();
|
||||
|
||||
/*! @method AsIOElement*/
|
||||
virtual AUIOElement* AsIOElement () { return this; }
|
||||
|
||||
protected:
|
||||
/*! @var mStreamFormat */
|
||||
CAStreamBasicDescription mStreamFormat;
|
||||
/*! @var mIOBuffer */
|
||||
AUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed
|
||||
// for output: output cache, usually allocated early on
|
||||
/*! @var mWillAllocate */
|
||||
bool mWillAllocate;
|
||||
};
|
||||
|
||||
// ____________________________________________________________________________
|
||||
//
|
||||
// AUScopeDelegates are a way to get virtual scopes.
|
||||
/*! @class AUScopeDelegate */
|
||||
class AUScopeDelegate {
|
||||
public:
|
||||
/*! @ctor AUScopeDelegate */
|
||||
AUScopeDelegate() : mCreator(NULL), mScope(0) { }
|
||||
/*! @dtor ~AUScopeDelegate */
|
||||
virtual ~AUScopeDelegate() {}
|
||||
|
||||
/*! @method Initialize */
|
||||
void Initialize( AUBase *creator,
|
||||
AudioUnitScope scope,
|
||||
UInt32 numElements)
|
||||
{
|
||||
mCreator = creator;
|
||||
mScope = scope;
|
||||
SetNumberOfElements(numElements);
|
||||
}
|
||||
|
||||
/*! @method SetNumberOfElements */
|
||||
virtual void SetNumberOfElements(UInt32 numElements) = 0;
|
||||
|
||||
/*! @method GetNumberOfElements */
|
||||
virtual UInt32 GetNumberOfElements() = 0;
|
||||
|
||||
/*! @method GetElement */
|
||||
virtual AUElement * GetElement(UInt32 elementIndex) = 0;
|
||||
|
||||
AUBase * GetCreator() const { return mCreator; }
|
||||
AudioUnitScope GetScope() const { return mScope; }
|
||||
|
||||
|
||||
private:
|
||||
/*! @var mCreator */
|
||||
AUBase * mCreator;
|
||||
/*! @var mScope */
|
||||
AudioUnitScope mScope;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ____________________________________________________________________________
|
||||
//
|
||||
/*! @class AUScope */
|
||||
class AUScope {
|
||||
public:
|
||||
/*! @ctor AUScope */
|
||||
AUScope() : mCreator(NULL), mScope(0), mDelegate(0) { }
|
||||
/*! @dtor ~AUScope */
|
||||
~AUScope();
|
||||
|
||||
/*! @method Initialize */
|
||||
void Initialize(AUBase *creator,
|
||||
AudioUnitScope scope,
|
||||
UInt32 numElements)
|
||||
{
|
||||
mCreator = creator;
|
||||
mScope = scope;
|
||||
|
||||
if (mDelegate)
|
||||
return mDelegate->Initialize(creator, scope, numElements);
|
||||
|
||||
SetNumberOfElements(numElements);
|
||||
}
|
||||
|
||||
/*! @method SetNumberOfElements */
|
||||
void SetNumberOfElements(UInt32 numElements);
|
||||
|
||||
/*! @method GetNumberOfElements */
|
||||
UInt32 GetNumberOfElements() const
|
||||
{
|
||||
if (mDelegate)
|
||||
return mDelegate->GetNumberOfElements();
|
||||
|
||||
return static_cast<UInt32>(mElements.size());
|
||||
}
|
||||
|
||||
/*! @method GetElement */
|
||||
AUElement * GetElement(UInt32 elementIndex) const
|
||||
{
|
||||
if (mDelegate)
|
||||
return mDelegate->GetElement(elementIndex);
|
||||
|
||||
ElementVector::const_iterator i = mElements.begin() + elementIndex;
|
||||
// catch passing -1 in as the elementIndex - causes a wrap around
|
||||
return (i >= mElements.end() || i < mElements.begin()) ? NULL : *i;
|
||||
}
|
||||
|
||||
/*! @method SafeGetElement */
|
||||
AUElement * SafeGetElement(UInt32 elementIndex)
|
||||
{
|
||||
AUElement *element = GetElement(elementIndex);
|
||||
if (element == NULL)
|
||||
COMPONENT_THROW(kAudioUnitErr_InvalidElement);
|
||||
return element;
|
||||
}
|
||||
|
||||
/*! @method GetIOElement */
|
||||
AUIOElement * GetIOElement(UInt32 elementIndex) const
|
||||
{
|
||||
AUElement *element = GetElement(elementIndex);
|
||||
AUIOElement *ioel = element ? element->AsIOElement () : NULL;
|
||||
if (!ioel)
|
||||
COMPONENT_THROW (kAudioUnitErr_InvalidElement);
|
||||
return ioel;
|
||||
}
|
||||
|
||||
/*! @method HasElementWithName */
|
||||
bool HasElementWithName () const;
|
||||
|
||||
/*! @method AddElementNamesToDict */
|
||||
void AddElementNamesToDict (CFMutableDictionaryRef & inNameDict);
|
||||
|
||||
bool RestoreElementNames (CFDictionaryRef& inNameDict);
|
||||
|
||||
AudioUnitScope GetScope() const { return mScope; }
|
||||
|
||||
void SetDelegate(AUScopeDelegate* inDelegate) { mDelegate = inDelegate; }
|
||||
|
||||
/*! @method SaveState */
|
||||
void SaveState(CFMutableDataRef data);
|
||||
|
||||
/*! @method RestoreState */
|
||||
const UInt8 * RestoreState(const UInt8 *state);
|
||||
|
||||
private:
|
||||
typedef std::vector<AUElement *> ElementVector;
|
||||
/*! @var mCreator */
|
||||
AUBase * mCreator;
|
||||
/*! @var mScope */
|
||||
AudioUnitScope mScope;
|
||||
/*! @var mElements */
|
||||
ElementVector mElements;
|
||||
/*! @var mDelegate */
|
||||
AUScopeDelegate * mDelegate;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __AUScopeElement_h__
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
File: AUSilentTimeout.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUSilentTimeout
|
||||
#define __AUSilentTimeout
|
||||
|
||||
class AUSilentTimeout
|
||||
{
|
||||
public:
|
||||
AUSilentTimeout()
|
||||
: mTimeoutCounter(0),
|
||||
mResetTimer(true)
|
||||
{};
|
||||
|
||||
void Process(UInt32 inFramesToProcess, UInt32 inTimeoutLimit, bool &ioSilence )
|
||||
{
|
||||
if(ioSilence )
|
||||
{
|
||||
if(mResetTimer )
|
||||
{
|
||||
mTimeoutCounter = inTimeoutLimit;
|
||||
mResetTimer = false;
|
||||
}
|
||||
|
||||
if(mTimeoutCounter > 0 )
|
||||
{
|
||||
mTimeoutCounter -= inFramesToProcess;
|
||||
ioSilence = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// signal to reset the next time we receive silence
|
||||
mResetTimer = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mResetTimer = true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
private:
|
||||
SInt32 mTimeoutCounter;
|
||||
bool mResetTimer;
|
||||
};
|
||||
|
||||
#endif // __AUSilentTimeout
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
File: AUTimestampGenerator.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUTimestampGenerator_h__
|
||||
#define __AUTimestampGenerator_h__
|
||||
|
||||
#include <math.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define TSGFMT "0x%10qx"
|
||||
//#define TSGFMT "%10qd"
|
||||
|
||||
// This class generates a continuously increasing series of timestamps based
|
||||
// on a series of potentially discontinuous timestamps (as can be delivered from
|
||||
// CoreAudio in the event of an overload or major engine change).
|
||||
// N.B.: "output" = downstream (source) timestamp
|
||||
// "input" = upstream (derived) timestamp
|
||||
class AUTimestampGenerator {
|
||||
public:
|
||||
AUTimestampGenerator(bool hostTimeDiscontinuityCorrection = false)
|
||||
{
|
||||
mState.mStartInputAtZero = true;
|
||||
mState.mBypassed = false;
|
||||
mState.mHostTimeDiscontinuityCorrection = hostTimeDiscontinuityCorrection;
|
||||
#if DEBUG
|
||||
mVerbosity = 0;
|
||||
snprintf(mDebugName, sizeof(mDebugName), "tsg @ %p", this);
|
||||
#endif
|
||||
// CAHostTimeBase should be used instead of the calls in <CoreAudio/HostTime.h>
|
||||
// we make this call here to ensure that this is initialized, otherwise the first time
|
||||
// you do actually call CAHostTimeBase to do work, can be on the render thread, and lead to unwanted VM faults
|
||||
CAHostTimeBase::GetFrequency();
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SetStartInputAtZero(bool b) { mState.mStartInputAtZero = b; }
|
||||
bool GetStartInputAtZero() const { return mState.mStartInputAtZero; }
|
||||
|
||||
// bypassing is intended for a narrow special case. the upstream sample time will always be the same as the downstream time.
|
||||
void SetBypassed(bool b) { mState.mBypassed = b; }
|
||||
bool GetBypassed() const { return mState.mBypassed; }
|
||||
|
||||
// Call this to reset the timeline.
|
||||
void Reset()
|
||||
{
|
||||
mState.mCurrentInputTime.mSampleTime = 0.;
|
||||
mState.mNextInputSampleTime = 0.;
|
||||
mState.mCurrentOutputTime.mSampleTime = 0.;
|
||||
mState.mNextOutputSampleTime = 0.;
|
||||
mState.mLastOutputTime.mFlags = 0;
|
||||
mState.mRateScalarAdj = 1.;
|
||||
|
||||
mFirstTime = true;
|
||||
#if DEBUG
|
||||
if (mVerbosity)
|
||||
printf("%-20.20s: Reset\n", mDebugName);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Call this once per render cycle with the downstream timestamp.
|
||||
// expectedDeltaFrames is the expected difference between the current and NEXT
|
||||
// downstream timestamps.
|
||||
// sampleRate is the OUTPUT sample rate.
|
||||
void AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj=1.0);
|
||||
|
||||
// Call this once per render cycle to obtain the upstream timestamp.
|
||||
// framesToAdvance is the number of frames the input timeline is to be
|
||||
// advanced during this render cycle.
|
||||
// sampleRate is the INPUT sample rate.
|
||||
const AudioTimeStamp & GenerateInputTime(Float64 framesToAdvance, double inputSampleRate, bool advanceHostTime = false);
|
||||
|
||||
// this can be called to override the setting of the next input sample time in GenerateInputTime
|
||||
void Advance(Float64 framesToAdvance)
|
||||
{
|
||||
#if DEBUG
|
||||
if (mVerbosity > 1)
|
||||
printf("%-20.20s: ADVANCE in = " TSGFMT " advance = " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentInputTime.mSampleTime, (SInt64)framesToAdvance);
|
||||
#endif
|
||||
mState.mNextInputSampleTime = mState.mCurrentInputTime.mSampleTime + framesToAdvance;
|
||||
}
|
||||
|
||||
struct State {
|
||||
AudioTimeStamp mCurrentInputTime;
|
||||
Float64 mNextInputSampleTime;
|
||||
Float64 mNextOutputSampleTime;
|
||||
Float64 mInputSampleTimeForOutputPull;
|
||||
|
||||
AudioTimeStamp mLastOutputTime;
|
||||
AudioTimeStamp mCurrentOutputTime;
|
||||
|
||||
bool mStartInputAtZero; // if true, input timeline starts at 0, else it starts
|
||||
// synced with the output timeline
|
||||
bool mDiscontinuous;
|
||||
bool mBypassed;
|
||||
Float64 mDiscontinuityDeltaSamples;
|
||||
|
||||
double mRateScalarAdj;
|
||||
|
||||
bool mHostTimeDiscontinuityCorrection; // If true, propagate timestamp discontinuities using host time.
|
||||
};
|
||||
|
||||
void GetState(State& outState) const { outState = mState; }
|
||||
void SetState(State const& inState) { mState = inState; mFirstTime = false; }
|
||||
|
||||
private:
|
||||
|
||||
struct State mState;
|
||||
|
||||
bool mFirstTime;
|
||||
|
||||
#if DEBUG
|
||||
public:
|
||||
int mVerbosity;
|
||||
char mDebugName[64];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif // __AUTimestampGenerator_h__
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
File: AUViewLocalizedStringKeys.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __AUViewLocalizedStringKeys_h__
|
||||
#define __AUViewLocalizedStringKeys_h__
|
||||
|
||||
// ACCESS POINT:
|
||||
#define kLocalizedStringBundle_AUView CFSTR("com.apple.audio.units.Components")
|
||||
#define kLocalizedStringTable_AUView CFSTR("CustomUI")
|
||||
|
||||
// UNLOCALIZED STRINGS:
|
||||
#define kAUViewUnlocalizedString_TitleSeparator CFSTR(": ")
|
||||
|
||||
// Generic View:
|
||||
#define kAUViewLocalizedStringKey_AudioUnit CFSTR("Audio Unit")
|
||||
#define kAUViewLocalizedStringKey_Manufacturer CFSTR("Manufacturer")
|
||||
|
||||
#define kAUViewLocalizedStringKey_FactoryPreset CFSTR("Factory Preset")
|
||||
|
||||
#define kAUViewLocalizedStringKey_Properties CFSTR("Properties")
|
||||
#define kAUViewLocalizedStringKey_Parameters CFSTR("Parameters")
|
||||
|
||||
#define kAUViewLocalizedStringKey_Standard CFSTR("Standard")
|
||||
#define kAUViewLocalizedStringKey_Expert CFSTR("Expert")
|
||||
|
||||
// AULoadCPU:
|
||||
#define kAUViewLocalizedStringKey_RestrictCPULoad CFSTR("Restrict CPU Load")
|
||||
#define kAUViewLocalizedStringKey_PercentSymbol CFSTR("%")
|
||||
#define kAUViewLocalizedStringKey_NotApplicable CFSTR("n/a")
|
||||
|
||||
// AUDiskStreamingCheckbox:
|
||||
#define kAUViewLocalizedStringKey_StreamFromDisk CFSTR("Stream From Disk")
|
||||
|
||||
// AURenderQualityPopup:
|
||||
#define kAUViewLocalizedStringKey_RenderQuality CFSTR("Render Quality")
|
||||
#define kAUViewLocalizedStringKey_Maximum CFSTR("Maximum")
|
||||
#define kAUViewLocalizedStringKey_High CFSTR("High")
|
||||
#define kAUViewLocalizedStringKey_Medium CFSTR("Medium")
|
||||
#define kAUViewLocalizedStringKey_Low CFSTR("Low")
|
||||
#define kAUViewLocalizedStringKey_Minimum CFSTR("Minimum")
|
||||
|
||||
// AUChannelLayoutPopUp:
|
||||
#define kAUViewLocalizedStringKey_AudioChannelLayout CFSTR("Audio Channel Layout")
|
||||
|
||||
#endif //__AUViewLocalizedStringKeys_h__
|
||||
|
|
@ -1,401 +0,0 @@
|
|||
/*
|
||||
File: CAAUParameter.cpp
|
||||
Abstract: CAAUParameter.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "CAAUParameter.h"
|
||||
|
||||
CAAUParameter::CAAUParameter()
|
||||
{
|
||||
memset(this, 0, sizeof(CAAUParameter));
|
||||
}
|
||||
|
||||
CAAUParameter::CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
|
||||
{
|
||||
memset(this, 0, sizeof(CAAUParameter));
|
||||
Init (au, param, scope, element);
|
||||
}
|
||||
|
||||
CAAUParameter::CAAUParameter (AudioUnitParameter &inParam)
|
||||
{
|
||||
memset(this, 0, sizeof(CAAUParameter));
|
||||
Init (inParam.mAudioUnit, inParam.mParameterID, inParam.mScope, inParam.mElement);
|
||||
}
|
||||
|
||||
CAAUParameter::CAAUParameter(const CAAUParameter &a)
|
||||
{
|
||||
memset(this, 0, sizeof(CAAUParameter));
|
||||
*this = a;
|
||||
}
|
||||
|
||||
CAAUParameter & CAAUParameter::operator = (const CAAUParameter &a)
|
||||
{
|
||||
if (mParamName) CFRelease(mParamName);
|
||||
if (mParamTag) CFRelease(mParamTag);
|
||||
if (mNamedParams) CFRelease(mNamedParams);
|
||||
|
||||
memcpy(this, &a, sizeof(CAAUParameter));
|
||||
|
||||
if (mParamName) CFRetain(mParamName);
|
||||
if (mParamTag) CFRetain(mParamTag);
|
||||
if (mNamedParams) CFRetain(mNamedParams);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAUParameter::~CAAUParameter()
|
||||
{
|
||||
if (mParamName) CFRelease(mParamName);
|
||||
if (mParamTag) CFRelease(mParamTag);
|
||||
if (mNamedParams) CFRelease (mNamedParams);
|
||||
}
|
||||
|
||||
void CAAUParameter::Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
|
||||
{
|
||||
mAudioUnit = au;
|
||||
mParameterID = param;
|
||||
mScope = scope;
|
||||
mElement = element;
|
||||
|
||||
UInt32 propertySize = sizeof(mParamInfo);
|
||||
OSStatus err = AudioUnitGetProperty(au, kAudioUnitProperty_ParameterInfo,
|
||||
scope, param, &mParamInfo, &propertySize);
|
||||
if (err)
|
||||
memset(&mParamInfo, 0, sizeof(mParamInfo));
|
||||
if (mParamInfo.flags & kAudioUnitParameterFlag_HasCFNameString) {
|
||||
mParamName = mParamInfo.cfNameString;
|
||||
if (!(mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease))
|
||||
CFRetain (mParamName);
|
||||
} else
|
||||
mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8);
|
||||
|
||||
const char* str = 0;
|
||||
switch (mParamInfo.unit)
|
||||
{
|
||||
case kAudioUnitParameterUnit_Boolean:
|
||||
str = "T/F";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Percent:
|
||||
case kAudioUnitParameterUnit_EqualPowerCrossfade:
|
||||
str = "%";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Seconds:
|
||||
str = "Secs";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_SampleFrames:
|
||||
str = "Samps";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Phase:
|
||||
case kAudioUnitParameterUnit_Degrees:
|
||||
str = "Degr.";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Hertz:
|
||||
str = "Hz";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Cents:
|
||||
case kAudioUnitParameterUnit_AbsoluteCents:
|
||||
str = "Cents";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_RelativeSemiTones:
|
||||
str = "S-T";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_MIDINoteNumber:
|
||||
case kAudioUnitParameterUnit_MIDIController:
|
||||
str = "MIDI";
|
||||
//these are inclusive, so add one value here
|
||||
mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Decibels:
|
||||
str = "dB";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_MixerFaderCurve1:
|
||||
case kAudioUnitParameterUnit_LinearGain:
|
||||
str = "Gain";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Pan:
|
||||
str = "L/R";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Meters:
|
||||
str = "Mtrs";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Octaves:
|
||||
str = "8ve";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_BPM:
|
||||
str = "BPM";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Beats:
|
||||
str = "Beats";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Milliseconds:
|
||||
str = "msecs";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Ratio:
|
||||
str = "Ratio";
|
||||
break;
|
||||
case kAudioUnitParameterUnit_Indexed:
|
||||
{
|
||||
propertySize = sizeof(mNamedParams);
|
||||
err = AudioUnitGetProperty (au,
|
||||
kAudioUnitProperty_ParameterValueStrings,
|
||||
scope,
|
||||
param,
|
||||
&mNamedParams,
|
||||
&propertySize);
|
||||
if (!err && mNamedParams) {
|
||||
mNumIndexedParams = CFArrayGetCount(mNamedParams);
|
||||
} else {
|
||||
//these are inclusive, so add one value here
|
||||
mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
|
||||
}
|
||||
str = NULL;
|
||||
}
|
||||
break;
|
||||
case kAudioUnitParameterUnit_CustomUnit:
|
||||
{
|
||||
CFStringRef unitName = mParamInfo.unitName;
|
||||
static char paramStr[256];
|
||||
CFStringGetCString (unitName, paramStr, 256, kCFStringEncodingUTF8);
|
||||
if (mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease)
|
||||
CFRelease (unitName);
|
||||
str = paramStr;
|
||||
break;
|
||||
}
|
||||
case kAudioUnitParameterUnit_Generic:
|
||||
case kAudioUnitParameterUnit_Rate:
|
||||
default:
|
||||
str = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (str)
|
||||
mParamTag = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
|
||||
else
|
||||
mParamTag = NULL;
|
||||
}
|
||||
|
||||
|
||||
Float32 CAAUParameter::GetValue() const
|
||||
{
|
||||
Float32 value = 0.;
|
||||
//OSStatus err =
|
||||
AudioUnitGetParameter(mAudioUnit, mParameterID, mScope, mElement, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue,
|
||||
const CAAUParameter * inParameter,
|
||||
UInt32 inDigits,
|
||||
UInt32 minDigits) {
|
||||
if (!inParameter) return nil;
|
||||
|
||||
AudioUnitParameterInfo info = inParameter->ParamInfo();
|
||||
int pow10;
|
||||
|
||||
switch (info.unit) {
|
||||
case kAudioUnitParameterUnit_Hertz:
|
||||
// number of significant digits based on value
|
||||
pow10 = int(log10(fmax(inParameterValue, .000001)));
|
||||
break;
|
||||
default:
|
||||
// number of significant digits based on parameter range
|
||||
pow10 = int(log10(fmax(double(info.maxValue - info.minValue), .000001)));
|
||||
break;
|
||||
}
|
||||
|
||||
// pow10 range nDigitsAfterDecimal
|
||||
// -2 .0100-.0999 4
|
||||
// -1 .100-.999 3
|
||||
// 0 1.00-9.99 2
|
||||
// 1 10.0-99.9 1
|
||||
// 2 100-999 0
|
||||
// 3 1000-9990 -1
|
||||
// 4 10000-99900 -2
|
||||
|
||||
int nDigitsAfterDecimal = inDigits - (pow10 + 1);
|
||||
if (nDigitsAfterDecimal < 0)
|
||||
nDigitsAfterDecimal = 0; // the least number of digits possible is zero
|
||||
|
||||
if (info.flags & kAudioUnitParameterFlag_IsHighResolution)
|
||||
nDigitsAfterDecimal = 4;
|
||||
|
||||
CFLocaleRef currentLocale = CFLocaleCopyCurrent();
|
||||
CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle);
|
||||
|
||||
CFNumberRef maxFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal);
|
||||
|
||||
if (nDigitsAfterDecimal > 0)
|
||||
nDigitsAfterDecimal = minDigits;
|
||||
|
||||
CFNumberRef minFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal);
|
||||
|
||||
CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMinFractionDigits, minFractionDigits);
|
||||
CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMaxFractionDigits, maxFractionDigits);
|
||||
CFStringRef formattedNumberString = CFNumberFormatterCreateStringWithValue (NULL, numberFormatter, kCFNumberDoubleType, &inParameterValue);
|
||||
|
||||
CFRelease(currentLocale);
|
||||
CFRelease(numberFormatter);
|
||||
CFRelease(maxFractionDigits);
|
||||
CFRelease(minFractionDigits);
|
||||
|
||||
return formattedNumberString;
|
||||
}
|
||||
|
||||
CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue,
|
||||
const CAAUParameter * inParameter,
|
||||
UInt32 inDigits) {
|
||||
return CreateLocalizedStringForParameterValue (inParameterValue, inParameter, inDigits, 1);
|
||||
}
|
||||
|
||||
double ValueForLocalizedParameterString (CFStringRef string, const CAAUParameter * inParameter) {
|
||||
CFLocaleRef currentLocale = CFLocaleCopyCurrent();
|
||||
CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle);
|
||||
|
||||
double value = 0;
|
||||
Boolean worked = CFNumberFormatterGetValueFromString (numberFormatter, string, NULL, kCFNumberDoubleType, &value);
|
||||
|
||||
CFRelease(currentLocale);
|
||||
CFRelease(numberFormatter);
|
||||
|
||||
if (worked)
|
||||
return value;
|
||||
else {
|
||||
AudioUnitParameterInfo info = inParameter->ParamInfo();
|
||||
return info.defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
CFStringRef CAAUParameter::GetStringFromValueCopy(const Float32 *value) const
|
||||
{
|
||||
if (HasNamedParams())
|
||||
{
|
||||
Float32 val = (value == NULL ? GetValue() : *value);
|
||||
int index = int(mParamInfo.minValue) + int(val);
|
||||
CFStringRef str = GetParamName (index);
|
||||
if (str) {
|
||||
CFRetain (str);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
else if (ValuesHaveStrings())
|
||||
{
|
||||
AudioUnitParameterStringFromValue stringValue;
|
||||
stringValue.inParamID = mParameterID;
|
||||
stringValue.inValue = value;
|
||||
stringValue.outString = NULL;
|
||||
UInt32 propertySize = sizeof(stringValue);
|
||||
|
||||
OSStatus err = AudioUnitGetProperty (mAudioUnit,
|
||||
kAudioUnitProperty_ParameterStringFromValue,
|
||||
mScope,
|
||||
0,
|
||||
&stringValue,
|
||||
&propertySize);
|
||||
|
||||
if (!err && stringValue.outString != NULL)
|
||||
return stringValue.outString;
|
||||
}
|
||||
|
||||
Float32 val = (value == NULL ? GetValue() : *value);
|
||||
AudioUnitParameterUnit unit = this->ParamInfo().unit;
|
||||
if (unit == kAudioUnitParameterUnit_Cents || unit == kAudioUnitParameterUnit_AbsoluteCents)
|
||||
return CreateLocalizedStringForParameterValue(val, this, 4, 0);
|
||||
else
|
||||
return CreateLocalizedStringForParameterValue(val, this, 4);
|
||||
}
|
||||
|
||||
Float32 CAAUParameter::GetValueFromString(CFStringRef str) const
|
||||
{
|
||||
if (ValuesHaveStrings())
|
||||
{
|
||||
AudioUnitParameterValueFromString valueString;
|
||||
valueString.inParamID = mParameterID;
|
||||
valueString.inString = str;
|
||||
UInt32 propertySize = sizeof(valueString);
|
||||
|
||||
OSStatus err = AudioUnitGetProperty (mAudioUnit,
|
||||
kAudioUnitProperty_ParameterValueFromString,
|
||||
mScope,
|
||||
0,
|
||||
&valueString,
|
||||
&propertySize);
|
||||
|
||||
if (!err) {
|
||||
return valueString.outValue;
|
||||
}
|
||||
}
|
||||
|
||||
return (Float32) ValueForLocalizedParameterString(str, this);
|
||||
}
|
||||
|
||||
void CAAUParameter::SetValue( AUParameterListenerRef inListener,
|
||||
void * inObject,
|
||||
Float32 inValue) const
|
||||
{
|
||||
// clip inValue as: maxValue >= inValue >= minValue before setting
|
||||
Float32 valueToSet = inValue;
|
||||
if (valueToSet > mParamInfo.maxValue)
|
||||
valueToSet = mParamInfo.maxValue;
|
||||
if (valueToSet < mParamInfo.minValue)
|
||||
valueToSet = mParamInfo.minValue;
|
||||
|
||||
AUParameterSet(inListener, inObject, this, valueToSet, 0);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void CAAUParameter::Print() const
|
||||
{
|
||||
UInt32 clump = 0;
|
||||
GetClumpID (clump);
|
||||
|
||||
UInt32 len = static_cast<UInt32>(CFStringGetLength(mParamName));
|
||||
char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars
|
||||
if (!CFStringGetCString (mParamName, chars, len * 2, kCFStringEncodingUTF8))
|
||||
chars[0] = 0;
|
||||
|
||||
printf ("ID: %ld, Clump: %u, Name: %s\n", (long unsigned int) mParameterID, (unsigned int) clump, chars);
|
||||
free (chars);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
File: CAAUParameter.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAAUParameter_h__
|
||||
#define __CAAUParameter_h__
|
||||
|
||||
#include <AudioToolbox/AudioUnitUtilities.h>
|
||||
|
||||
// ____________________________________________________________________________
|
||||
// CAAUParameter
|
||||
// complete parameter specification
|
||||
/*! @class CAAUParameter */
|
||||
class CAAUParameter : public AudioUnitParameter {
|
||||
public:
|
||||
/*! @ctor CAAUParameter.0 */
|
||||
CAAUParameter();
|
||||
/*! @ctor CAAUParameter.1 */
|
||||
CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element);
|
||||
/*! @ctor CAAUParameter.2 */
|
||||
CAAUParameter(AudioUnitParameter &inParam);
|
||||
/*! @ctor CAAUParameter.3 */
|
||||
CAAUParameter(const CAAUParameter &a);
|
||||
/*! @dtor ~CAAUParameter */
|
||||
~CAAUParameter();
|
||||
|
||||
/*! @method operator <@ */
|
||||
bool operator < (const CAAUParameter &a) const
|
||||
{
|
||||
return memcmp(this, &a, sizeof(AudioUnitParameter)) < 0;
|
||||
}
|
||||
|
||||
/*! @method operator ==@ */
|
||||
bool operator == (const CAAUParameter &a) const
|
||||
{
|
||||
return !memcmp(this, &a, sizeof(AudioUnitParameter));
|
||||
}
|
||||
|
||||
/*! @method operator =@ */
|
||||
CAAUParameter & operator = (const CAAUParameter &a);
|
||||
|
||||
/*! @method GetValue */
|
||||
Float32 GetValue() const;
|
||||
/*! @method SetValue */
|
||||
void SetValue( AUParameterListenerRef inListener,
|
||||
void * inObject,
|
||||
Float32 inValue) const;
|
||||
|
||||
/*! @method GetName */
|
||||
CFStringRef GetName() const { return mParamName; }
|
||||
// borrowed reference!
|
||||
|
||||
/*! @method GetStringFromValueCopy */
|
||||
CFStringRef GetStringFromValueCopy(const Float32 *value = NULL) const;
|
||||
// returns a copy of the name of the current parameter value
|
||||
// or null if there is no name associated
|
||||
// caller must release
|
||||
/*! @method ValuesHaveStrings */
|
||||
bool ValuesHaveStrings () const
|
||||
{
|
||||
return (mParamInfo.flags & kAudioUnitParameterFlag_ValuesHaveStrings) != 0;
|
||||
}
|
||||
|
||||
/*! @method GetValueFromString */
|
||||
Float32 GetValueFromString (CFStringRef str) const;
|
||||
// caller must release
|
||||
|
||||
/*! @method ParamInfo */
|
||||
const AudioUnitParameterInfo &
|
||||
ParamInfo() const { return mParamInfo; }
|
||||
|
||||
/*! @method GetParamTag */
|
||||
CFStringRef GetParamTag() const { return mParamTag; }
|
||||
// this may return null! -
|
||||
// in which case there is no descriptive tag for the parameter
|
||||
|
||||
/*! @method GetParamName */
|
||||
CFStringRef GetParamName (int inIndex) const
|
||||
// this can return null if there is no name for the parameter
|
||||
{
|
||||
return (mNamedParams && inIndex < mNumIndexedParams)
|
||||
? (CFStringRef) CFArrayGetValueAtIndex(mNamedParams, inIndex)
|
||||
: 0;
|
||||
}
|
||||
|
||||
/*! @method GetNumIndexedParams */
|
||||
int GetNumIndexedParams () const { return mNumIndexedParams; }
|
||||
|
||||
/*! @method IsIndexedParam */
|
||||
bool IsIndexedParam () const { return mNumIndexedParams != 0; }
|
||||
|
||||
/*! @method HasNamedParams */
|
||||
bool HasNamedParams () const { return IsIndexedParam() && mNamedParams; }
|
||||
|
||||
/*! @method GetClumpID */
|
||||
bool GetClumpID (UInt32 &outClumpID) const
|
||||
{
|
||||
if (mParamInfo.flags & kAudioUnitParameterFlag_HasClump) {
|
||||
outClumpID = mParamInfo.clumpID;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @method HasDisplayTransformation */
|
||||
bool HasDisplayTransformation () const
|
||||
{
|
||||
return GetAudioUnitParameterDisplayType (mParamInfo.flags);
|
||||
}
|
||||
|
||||
/*! @method IsExpert */
|
||||
bool IsExpert () const
|
||||
{
|
||||
return mParamInfo.flags & kAudioUnitParameterFlag_ExpertMode;
|
||||
}
|
||||
#if DEBUG
|
||||
void Print () const;
|
||||
#endif
|
||||
|
||||
// these methods are defined in CAPersistence.cpp
|
||||
// they will persist and restore only the scope, element and param ID's of the AudioUnitParameter
|
||||
// however, this is sufficient to be able to save/restore a CAAUParameter object
|
||||
void Save (CFPropertyListRef &outData) const;
|
||||
|
||||
static void Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData);
|
||||
|
||||
static OSStatus Restore (const CFPropertyListRef inData, AudioUnitParameter &outParam);
|
||||
|
||||
protected:
|
||||
// cached parameter info
|
||||
/*! @var mParamInfo */
|
||||
AudioUnitParameterInfo mParamInfo;
|
||||
/*! @var mParamName */
|
||||
CFStringRef mParamName;
|
||||
/*! @var mParamTag */
|
||||
CFStringRef mParamTag;
|
||||
/*! @var mNumIndexedParams */
|
||||
short mNumIndexedParams;
|
||||
/*! @var mNamedParams */
|
||||
CFArrayRef mNamedParams;
|
||||
|
||||
private:
|
||||
void Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __CAAUParameter_h__
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
/*
|
||||
File: CAAtomic.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
/*
|
||||
This file implements all Atomic operations using Interlocked functions specified in
|
||||
Winbase.h
|
||||
NOTE: According to Microsoft documentation, all Interlocked functions generates a
|
||||
full barrier.
|
||||
On Windows:
|
||||
As the Interlocked functions returns the Old value, Extra checks and operations
|
||||
are made after the atomic operation to return value consistent with OSX counterparts.
|
||||
*/
|
||||
#ifndef __CAAtomic_h__
|
||||
#define __CAAtomic_h__
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_InterlockedOr)
|
||||
#pragma intrinsic(_InterlockedAnd)
|
||||
#else
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#endif
|
||||
|
||||
inline void CAMemoryBarrier()
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
MemoryBarrier();
|
||||
#else
|
||||
OSMemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt);
|
||||
// InterlockedExchangeAdd returns the original value which differs from OSX version.
|
||||
// At this point the addition would have occured and hence returning the new value
|
||||
// to keep it sync with OSX.
|
||||
return lRetVal + theAmt;
|
||||
#else
|
||||
return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
|
||||
// function instead.
|
||||
long j = _InterlockedOr((volatile long*)theValue, theMask);
|
||||
// _InterlockedOr returns the original value which differs from OSX version.
|
||||
// Returning the new value similar to OSX
|
||||
return (SInt32)(j | theMask);
|
||||
#else
|
||||
return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
|
||||
// function instead.
|
||||
long j = _InterlockedAnd((volatile long*)theValue, theMask);
|
||||
// _InterlockedAnd returns the original value which differs from OSX version.
|
||||
// Returning the new value similar to OSX
|
||||
return (SInt32)(j & theMask);
|
||||
#else
|
||||
return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
// InterlockedCompareExchange returns the old value. But we need to return bool value.
|
||||
long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue);
|
||||
// Hence we check if the new value is set and if it is we return true else false.
|
||||
// If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen.
|
||||
return (oldValue == lRetVal);
|
||||
#else
|
||||
return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return (SInt32)InterlockedIncrement((volatile long*)theValue);
|
||||
#else
|
||||
return OSAtomicIncrement32((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return (SInt32)InterlockedDecrement((volatile long*)theValue);
|
||||
#else
|
||||
return OSAtomicDecrement32((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return CAAtomicIncrement32(theValue);
|
||||
#else
|
||||
return OSAtomicIncrement32Barrier((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return CAAtomicDecrement32(theValue);
|
||||
#else
|
||||
return OSAtomicDecrement32Barrier((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear);
|
||||
return (bOldVal ? true : false);
|
||||
#else
|
||||
return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress);
|
||||
return (bOldVal ? true : false);
|
||||
#else
|
||||
return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet);
|
||||
return (bOldVal ? true : false);
|
||||
#else
|
||||
return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
// int32_t flavors -- for C++ only since we can't overload in C
|
||||
// CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then
|
||||
// this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where
|
||||
// SInt32 is defined as signed long so this would work there.
|
||||
// So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included.
|
||||
#if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__
|
||||
inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue)
|
||||
{
|
||||
return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue)
|
||||
{
|
||||
return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue)
|
||||
{
|
||||
return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicIncrement32(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicIncrement32((volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicDecrement32(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicDecrement32((volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue);
|
||||
}
|
||||
#endif // __cplusplus && !__LP64__
|
||||
|
||||
#if __LP64__
|
||||
inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue )
|
||||
{
|
||||
return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool CAAtomicCompareAndSwapPtrBarrier(void *__oldValue, void *__newValue, volatile void ** __theValue)
|
||||
{
|
||||
#if __LP64__
|
||||
return CAAtomicCompareAndSwap64Barrier((int64_t)__oldValue, (int64_t)__newValue, (int64_t *)__theValue);
|
||||
#else
|
||||
return CAAtomicCompareAndSwap32Barrier((int32_t)__oldValue, (int32_t)__newValue, (int32_t *)__theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Spinlocks. These use memory barriers as required to synchronize access to shared
|
||||
* memory protected by the lock. The lock operation spins, but employs various strategies
|
||||
* to back off if the lock is held, making it immune to most priority-inversion livelocks.
|
||||
* The try operation immediately returns false if the lock was held, true if it took the
|
||||
* lock. The convention is that unlocked is zero, locked is nonzero.
|
||||
*/
|
||||
#define CA_SPINLOCK_INIT 0
|
||||
|
||||
typedef int32_t CASpinLock;
|
||||
|
||||
bool CASpinLockTry( volatile CASpinLock *__lock );
|
||||
void CASpinLockLock( volatile CASpinLock *__lock );
|
||||
void CASpinLockUnlock( volatile CASpinLock *__lock );
|
||||
|
||||
inline void CASpinLockLock( volatile CASpinLock *__lock )
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSSpinLockLock(__lock);
|
||||
#else
|
||||
while (CAAtomicTestAndSetBarrier(0, (void*)__lock))
|
||||
usleep(1000); // ???
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void CASpinLockUnlock( volatile CASpinLock *__lock )
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSSpinLockUnlock(__lock);
|
||||
#else
|
||||
CAAtomicTestAndClearBarrier(0, (void*)__lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CASpinLockTry( volatile CASpinLock *__lock )
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
return OSSpinLockTry(__lock);
|
||||
#else
|
||||
return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif // __CAAtomic_h__
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
/*
|
||||
File: CAAtomicStack.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAAtomicStack_h__
|
||||
#define __CAAtomicStack_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <libkern/OSAtomic.h>
|
||||
#else
|
||||
#include <CAAtomic.h>
|
||||
#endif
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
// linked list LIFO or FIFO (pop_all_reversed) stack, elements are pushed and popped atomically
|
||||
// class T must implement T *& next().
|
||||
template <class T>
|
||||
class TAtomicStack {
|
||||
public:
|
||||
TAtomicStack() : mHead(NULL) { }
|
||||
|
||||
// non-atomic routines, for use when initializing/deinitializing, operate NON-atomically
|
||||
void push_NA(T *item)
|
||||
{
|
||||
item->next() = mHead;
|
||||
mHead = item;
|
||||
}
|
||||
|
||||
T * pop_NA()
|
||||
{
|
||||
T *result = mHead;
|
||||
if (result)
|
||||
mHead = result->next();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const { return mHead == NULL; }
|
||||
|
||||
T * head() { return mHead; }
|
||||
|
||||
// atomic routines
|
||||
void push_atomic(T *item)
|
||||
{
|
||||
T *head_;
|
||||
do {
|
||||
head_ = mHead;
|
||||
item->next() = head_;
|
||||
} while (!compare_and_swap(head_, item, &mHead));
|
||||
}
|
||||
|
||||
void push_multiple_atomic(T *item)
|
||||
// pushes entire linked list headed by item
|
||||
{
|
||||
T *head_, *p = item, *tail;
|
||||
// find the last one -- when done, it will be linked to head
|
||||
do {
|
||||
tail = p;
|
||||
p = p->next();
|
||||
} while (p);
|
||||
do {
|
||||
head_ = mHead;
|
||||
tail->next() = head_;
|
||||
} while (!compare_and_swap(head_, item, &mHead));
|
||||
}
|
||||
|
||||
T * pop_atomic_single_reader()
|
||||
// this may only be used when only one thread may potentially pop from the stack.
|
||||
// if multiple threads may pop, this suffers from the ABA problem.
|
||||
// <rdar://problem/4606346> TAtomicStack suffers from the ABA problem
|
||||
{
|
||||
T *result;
|
||||
do {
|
||||
if ((result = mHead) == NULL)
|
||||
break;
|
||||
} while (!compare_and_swap(result, result->next(), &mHead));
|
||||
return result;
|
||||
}
|
||||
|
||||
T * pop_atomic()
|
||||
// This is inefficient for large linked lists.
|
||||
// prefer pop_all() to a series of calls to pop_atomic.
|
||||
// push_multiple_atomic has to traverse the entire list.
|
||||
{
|
||||
T *result = pop_all();
|
||||
if (result) {
|
||||
T *next = result->next();
|
||||
if (next)
|
||||
// push all the remaining items back onto the stack
|
||||
push_multiple_atomic(next);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
T * pop_all()
|
||||
{
|
||||
T *result;
|
||||
do {
|
||||
if ((result = mHead) == NULL)
|
||||
break;
|
||||
} while (!compare_and_swap(result, NULL, &mHead));
|
||||
return result;
|
||||
}
|
||||
|
||||
T* pop_all_reversed()
|
||||
{
|
||||
TAtomicStack<T> reversed;
|
||||
T *p = pop_all(), *next;
|
||||
while (p != NULL) {
|
||||
next = p->next();
|
||||
reversed.push_NA(p);
|
||||
p = next;
|
||||
}
|
||||
return reversed.mHead;
|
||||
}
|
||||
|
||||
static bool compare_and_swap(T *oldvalue, T *newvalue, T **pvalue)
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
#if __LP64__
|
||||
return ::OSAtomicCompareAndSwap64Barrier(int64_t(oldvalue), int64_t(newvalue), (int64_t *)pvalue);
|
||||
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||
return ::OSAtomicCompareAndSwap32Barrier(int32_t(oldvalue), int32_t(newvalue), (int32_t *)pvalue);
|
||||
#else
|
||||
return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
|
||||
#endif
|
||||
#else
|
||||
//return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
|
||||
return CAAtomicCompareAndSwap32Barrier(SInt32(oldvalue), SInt32(newvalue), (SInt32*)pvalue);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
T * mHead;
|
||||
};
|
||||
|
||||
#if ((MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) && !TARGET_OS_WIN32)
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
class CAAtomicStack {
|
||||
public:
|
||||
CAAtomicStack(size_t nextPtrOffset) : mNextPtrOffset(nextPtrOffset) {
|
||||
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
|
||||
mHead.opaque1 = 0; mHead.opaque2 = 0;
|
||||
}
|
||||
// a subset of the above
|
||||
void push_atomic(void *p) { OSAtomicEnqueue(&mHead, p, mNextPtrOffset); }
|
||||
void push_NA(void *p) { push_atomic(p); }
|
||||
|
||||
void * pop_atomic() { return OSAtomicDequeue(&mHead, mNextPtrOffset); }
|
||||
void * pop_atomic_single_reader() { return pop_atomic(); }
|
||||
void * pop_NA() { return pop_atomic(); }
|
||||
|
||||
private:
|
||||
OSQueueHead mHead;
|
||||
size_t mNextPtrOffset;
|
||||
};
|
||||
|
||||
// a more efficient subset of TAtomicStack using OSQueue.
|
||||
template <class T>
|
||||
class TAtomicStack2 {
|
||||
public:
|
||||
TAtomicStack2() {
|
||||
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
|
||||
mHead.opaque1 = 0; mHead.opaque2 = 0;
|
||||
mNextPtrOffset = -1;
|
||||
}
|
||||
void push_atomic(T *item) {
|
||||
if (mNextPtrOffset < 0) {
|
||||
T **pnext = &item->next(); // hack around offsetof not working with C++
|
||||
mNextPtrOffset = (Byte *)pnext - (Byte *)item;
|
||||
}
|
||||
OSAtomicEnqueue(&mHead, item, mNextPtrOffset);
|
||||
}
|
||||
void push_NA(T *item) { push_atomic(item); }
|
||||
|
||||
T * pop_atomic() { return (T *)OSAtomicDequeue(&mHead, mNextPtrOffset); }
|
||||
T * pop_atomic_single_reader() { return pop_atomic(); }
|
||||
T * pop_NA() { return pop_atomic(); }
|
||||
|
||||
// caution: do not try to implement pop_all_reversed here. the writer could add new elements
|
||||
// while the reader is trying to pop old ones!
|
||||
|
||||
private:
|
||||
OSQueueHead mHead;
|
||||
ssize_t mNextPtrOffset;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define TAtomicStack2 TAtomicStack
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED && !TARGET_OS_WIN32
|
||||
|
||||
#endif // __CAAtomicStack_h__
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
File: CAAudioChannelLayout.cpp
|
||||
Abstract: CAAudioChannelLayout.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CAAudioChannelLayout.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
|
||||
AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions)
|
||||
{
|
||||
UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions);
|
||||
AudioChannelLayout* theAnswer = static_cast<AudioChannelLayout*>(CA_calloc(1, theSize));
|
||||
if(theAnswer != NULL)
|
||||
{
|
||||
SetAllToUnknown(*theAnswer, inNumberChannelDescriptions);
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout)
|
||||
{
|
||||
free(inChannelLayout);
|
||||
}
|
||||
|
||||
void CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions)
|
||||
{
|
||||
outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
outChannelLayout.mChannelBitmap = 0;
|
||||
outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions;
|
||||
for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex)
|
||||
{
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y)
|
||||
{
|
||||
// compare based on the number of channel descriptions present
|
||||
// (this may be too strict a comparison if all you care about are matching layout tags)
|
||||
UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions);
|
||||
UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions);
|
||||
|
||||
if (theSize1 != theSize2)
|
||||
return false;
|
||||
|
||||
return !memcmp (&x, &y, theSize1);
|
||||
}
|
||||
|
||||
bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
// counting the one bits in a word
|
||||
inline UInt32 CountOnes(UInt32 x)
|
||||
{
|
||||
// secret magic algorithm for counting bits in a word.
|
||||
UInt32 t;
|
||||
x = x - ((x >> 1) & 0x55555555);
|
||||
t = ((x >> 2) & 0x33333333);
|
||||
x = (x & 0x33333333) + t;
|
||||
x = (x + (x >> 4)) & 0x0F0F0F0F;
|
||||
x = x + (x << 8);
|
||||
x = x + (x << 16);
|
||||
return x >> 24;
|
||||
}
|
||||
|
||||
UInt32 CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout)
|
||||
{
|
||||
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
|
||||
return inLayout.mNumberChannelDescriptions;
|
||||
|
||||
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
|
||||
return CountOnes (inLayout.mChannelBitmap);
|
||||
|
||||
return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag);
|
||||
}
|
||||
|
||||
void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout)
|
||||
{
|
||||
if (layout == NULL)
|
||||
{
|
||||
fprintf (file, "\tNULL layout\n");
|
||||
return;
|
||||
}
|
||||
fprintf (file, "\tTag=0x%X, ", (int)layout->mChannelLayoutTag);
|
||||
if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
|
||||
fprintf (file, "Using Bitmap:0x%X\n", (int)layout->mChannelBitmap);
|
||||
else {
|
||||
fprintf (file, "Num Chan Descs=%d\n", (int)layout->mNumberChannelDescriptions);
|
||||
const AudioChannelDescription *desc = layout->mChannelDescriptions;
|
||||
for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) {
|
||||
fprintf (file, "\t\tLabel=%d, Flags=0x%X, ", (int)desc->mChannelLabel, (int)desc->mChannelFlags);
|
||||
fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
File: CAAudioChannelLayout.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAAudioChannelLayout_h__)
|
||||
#define __CAAudioChannelLayout_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CoreFoundation.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
|
||||
#if !HAL_Build
|
||||
#include "CAReferenceCounted.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
|
||||
bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y);
|
||||
bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y);
|
||||
|
||||
extern "C" void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout);
|
||||
|
||||
class CAAudioChannelLayout
|
||||
{
|
||||
// static Construction/Destruction
|
||||
public:
|
||||
static AudioChannelLayout* Create(UInt32 inNumberChannelDescriptions);
|
||||
static void Destroy(AudioChannelLayout* inChannelLayout);
|
||||
static UInt32 CalculateByteSize(UInt32 inNumberChannelDescriptions) {
|
||||
return SizeOf32(AudioChannelLayout) - SizeOf32(AudioChannelDescription) + (inNumberChannelDescriptions * SizeOf32(AudioChannelDescription));
|
||||
}
|
||||
static void SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions);
|
||||
static UInt32 NumberChannels(const AudioChannelLayout& inLayout);
|
||||
|
||||
#if !HAL_Build
|
||||
// object methods
|
||||
public:
|
||||
CAAudioChannelLayout ();
|
||||
|
||||
CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
|
||||
// if inChooseSurround is false, then symmetrical speaker arrangements
|
||||
// are chosen in place of surround layouts if there is a choice
|
||||
// This call chooses layouts based on the expected defaults in
|
||||
// AudioUnit usage
|
||||
CAAudioChannelLayout (AudioChannelLayoutTag inTag);
|
||||
CAAudioChannelLayout (const CAAudioChannelLayout &c);
|
||||
CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout);
|
||||
~CAAudioChannelLayout();
|
||||
|
||||
CAAudioChannelLayout& operator= (const AudioChannelLayout* inChannelLayout);
|
||||
CAAudioChannelLayout& operator= (const CAAudioChannelLayout& c);
|
||||
bool operator== (const CAAudioChannelLayout &c) const;
|
||||
bool operator!= (const CAAudioChannelLayout &c) const;
|
||||
|
||||
void SetWithTag(AudioChannelLayoutTag inTag);
|
||||
|
||||
bool IsValid() const { return NumberChannels() > 0; }
|
||||
UInt32 Size() const { return mLayout ? mLayout->Size() : 0; }
|
||||
|
||||
UInt32 NumberChannels() const { return mLayout ? mLayout->NumberChannels() : 0; }
|
||||
|
||||
AudioChannelLayoutTag Tag() const { return Layout().mChannelLayoutTag; }
|
||||
const AudioChannelLayout& Layout() const { return mLayout->Layout(); }
|
||||
operator const AudioChannelLayout *() const { return &Layout(); }
|
||||
|
||||
void Print () const { Print (stdout); }
|
||||
void Print (FILE* file) const;
|
||||
|
||||
OSStatus Save (CFPropertyListRef *outData) const;
|
||||
OSStatus Restore (CFPropertyListRef &inData);
|
||||
|
||||
private:
|
||||
class RefCountedLayout : public CAReferenceCounted {
|
||||
void * operator new(size_t /* size */, size_t aclSize)
|
||||
{
|
||||
return CA_malloc(sizeof(RefCountedLayout) - sizeof(AudioChannelLayout) + aclSize);
|
||||
}
|
||||
|
||||
void operator delete(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
|
||||
RefCountedLayout(UInt32 inDataSize) :
|
||||
mByteSize(inDataSize)
|
||||
{
|
||||
memset(&mACL, 0, inDataSize);
|
||||
}
|
||||
|
||||
public:
|
||||
static RefCountedLayout *CreateWithNumberChannelDescriptions(unsigned nChannels) {
|
||||
size_t size = CAAudioChannelLayout::CalculateByteSize(nChannels);
|
||||
return new(size) RefCountedLayout((UInt32)size);
|
||||
}
|
||||
|
||||
static RefCountedLayout *CreateWithLayout(const AudioChannelLayout *layout) {
|
||||
size_t size = CAAudioChannelLayout::CalculateByteSize(layout->mNumberChannelDescriptions);
|
||||
RefCountedLayout *acl = new(size) RefCountedLayout((UInt32)size);
|
||||
memcpy(&acl->mACL, layout, size);
|
||||
return acl;
|
||||
}
|
||||
static RefCountedLayout *CreateWithLayoutTag(AudioChannelLayoutTag layoutTag) {
|
||||
RefCountedLayout *acl = CreateWithNumberChannelDescriptions(0);
|
||||
acl->mACL.mChannelLayoutTag = layoutTag;
|
||||
return acl;
|
||||
}
|
||||
|
||||
const AudioChannelLayout & Layout() const { return mACL; }
|
||||
|
||||
UInt32 Size () const { return mByteSize; }
|
||||
|
||||
UInt32 NumberChannels() { return CAAudioChannelLayout::NumberChannels(Layout()); }
|
||||
|
||||
private:
|
||||
const UInt32 mByteSize;
|
||||
AudioChannelLayout mACL;
|
||||
// * * * mACL is variable length and thus must be last * * *
|
||||
|
||||
// only the constructors can change the actual state of the layout
|
||||
friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
|
||||
friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData);
|
||||
friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout);
|
||||
friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag);
|
||||
|
||||
AudioChannelLayout * GetLayout() { return &mACL; }
|
||||
|
||||
private:
|
||||
// prohibited methods: private and unimplemented.
|
||||
RefCountedLayout();
|
||||
RefCountedLayout(const RefCountedLayout& c);
|
||||
RefCountedLayout& operator=(const RefCountedLayout& c);
|
||||
};
|
||||
|
||||
RefCountedLayout *mLayout;
|
||||
#endif // HAL_Build
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,508 +0,0 @@
|
|||
/*
|
||||
File: CAAutoDisposer.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAPtr_h__)
|
||||
#define __CAPtr_h__
|
||||
|
||||
#include <stdlib.h> // for malloc
|
||||
#include <new> // for bad_alloc
|
||||
#include <string.h> // for memset
|
||||
|
||||
inline void* CA_malloc(size_t size)
|
||||
{
|
||||
void* p = malloc(size);
|
||||
if (!p && size) throw std::bad_alloc();
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void* CA_realloc(void* old, size_t size)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
void* p = realloc(old, size);
|
||||
#else
|
||||
void* p = reallocf(old, size); // reallocf ensures the old pointer is freed if memory is full (p is NULL).
|
||||
#endif
|
||||
if (!p && size) throw std::bad_alloc();
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifndef UINTPTR_MAX
|
||||
#if __LP64__
|
||||
#define UINTPTR_MAX 18446744073709551615ULL
|
||||
#else
|
||||
#define UINTPTR_MAX 4294967295U
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline void* CA_calloc(size_t n, size_t size)
|
||||
{
|
||||
// ensure that multiplication will not overflow
|
||||
if (n && UINTPTR_MAX / n < size) throw std::bad_alloc();
|
||||
|
||||
size_t nsize = n*size;
|
||||
void* p = malloc(nsize);
|
||||
if (!p && nsize) throw std::bad_alloc();
|
||||
|
||||
memset(p, 0, nsize);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// helper class for automatic conversions
|
||||
template <typename T>
|
||||
struct CAPtrRef
|
||||
{
|
||||
T* ptr_;
|
||||
|
||||
explicit CAPtrRef(T* ptr) : ptr_(ptr) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CAAutoFree
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
|
||||
CAAutoFree() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoFree(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoFree(CAAutoFree<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoFree(CAAutoFree<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
CAAutoFree(size_t n, bool clear = false)
|
||||
// this becomes an ambiguous call if n == 0
|
||||
: ptr_(0)
|
||||
{
|
||||
size_t maxItems = ~size_t(0) / sizeof(T);
|
||||
if (n > maxItems)
|
||||
throw std::bad_alloc();
|
||||
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(n, sizeof(T)) : CA_malloc(n * sizeof(T)));
|
||||
}
|
||||
|
||||
~CAAutoFree() { free(); }
|
||||
|
||||
void alloc(size_t numItems, bool clear = false)
|
||||
{
|
||||
size_t maxItems = ~size_t(0) / sizeof(T);
|
||||
if (numItems > maxItems) throw std::bad_alloc();
|
||||
|
||||
free();
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
void allocBytes(size_t numBytes, bool clear = false)
|
||||
{
|
||||
free();
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes));
|
||||
}
|
||||
|
||||
void reallocBytes(size_t numBytes)
|
||||
{
|
||||
ptr_ = static_cast<T*>(CA_realloc(ptr_, numBytes));
|
||||
}
|
||||
|
||||
void reallocItems(size_t numItems)
|
||||
{
|
||||
size_t maxItems = ~size_t(0) / sizeof(T);
|
||||
if (numItems > maxItems) throw std::bad_alloc();
|
||||
|
||||
ptr_ = static_cast<T*>(CA_realloc(ptr_, numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoFree& operator=(CAAutoFree<U>& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoFree& operator=(CAAutoFree& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoFree& operator=(T* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoFree& operator=(U* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator()() const { return ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
|
||||
bool operator==(CAAutoFree const& that) const { return ptr_ == that.ptr_; }
|
||||
bool operator!=(CAAutoFree const& that) const { return ptr_ != that.ptr_; }
|
||||
bool operator==(T* ptr) const { return ptr_ == ptr; }
|
||||
bool operator!=(T* ptr) const { return ptr_ != ptr; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
// release ownership
|
||||
T* result = ptr_;
|
||||
ptr_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(T* ptr)
|
||||
{
|
||||
if (ptr != ptr_)
|
||||
{
|
||||
::free(ptr_);
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
// automatic conversions to allow assignment from results of functions.
|
||||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book.
|
||||
CAAutoFree(CAPtrRef<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoFree& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoDelete(CAAutoDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoDelete(CAAutoDelete<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
~CAAutoDelete() { free(); }
|
||||
|
||||
template <typename U>
|
||||
CAAutoDelete& operator=(CAAutoDelete<U>& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoDelete& operator=(CAAutoDelete& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoDelete& operator=(T* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoDelete& operator=(U* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator()() const { return ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
|
||||
bool operator==(CAAutoDelete const& that) const { return ptr_ == that.ptr_; }
|
||||
bool operator!=(CAAutoDelete const& that) const { return ptr_ != that.ptr_; }
|
||||
bool operator==(T* ptr) const { return ptr_ == ptr; }
|
||||
bool operator!=(T* ptr) const { return ptr_ != ptr; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
// release ownership
|
||||
T* result = ptr_;
|
||||
ptr_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(T* ptr)
|
||||
{
|
||||
if (ptr != ptr_)
|
||||
{
|
||||
delete ptr_;
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
// automatic conversions to allow assignment from results of functions.
|
||||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book.
|
||||
CAAutoDelete(CAPtrRef<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoArrayDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoArrayDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// this becomes an ambiguous call if n == 0
|
||||
CAAutoArrayDelete(size_t n) : ptr_(new T[n]) {}
|
||||
|
||||
~CAAutoArrayDelete() { free(); }
|
||||
|
||||
void alloc(size_t numItems)
|
||||
{
|
||||
free();
|
||||
ptr_ = new T [numItems];
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoArrayDelete& operator=(CAAutoArrayDelete<U>& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoArrayDelete& operator=(CAAutoArrayDelete& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoArrayDelete& operator=(T* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoArrayDelete& operator=(U* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator()() const { return ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
|
||||
bool operator==(CAAutoArrayDelete const& that) const { return ptr_ == that.ptr_; }
|
||||
bool operator!=(CAAutoArrayDelete const& that) const { return ptr_ != that.ptr_; }
|
||||
bool operator==(T* ptr) const { return ptr_ == ptr; }
|
||||
bool operator!=(T* ptr) const { return ptr_ != ptr; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
// release ownership
|
||||
T* result = ptr_;
|
||||
ptr_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(T* ptr)
|
||||
{
|
||||
if (ptr != ptr_)
|
||||
{
|
||||
delete [] ptr_;
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
// automatic conversions to allow assignment from results of functions.
|
||||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book.
|
||||
CAAutoArrayDelete(CAPtrRef<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoArrayDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoArrayDelete<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// convenience function
|
||||
template <typename T>
|
||||
void free(CAAutoFree<T>& p)
|
||||
{
|
||||
p.free();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
// example program showing ownership transfer
|
||||
|
||||
CAAutoFree<char> source()
|
||||
{
|
||||
// source allocates and returns ownership to the caller.
|
||||
const char* str = "this is a test";
|
||||
size_t size = strlen(str) + 1;
|
||||
CAAutoFree<char> captr(size, false);
|
||||
strlcpy(captr(), str, size);
|
||||
printf("source %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
return captr;
|
||||
}
|
||||
|
||||
void user(CAAutoFree<char> const& captr)
|
||||
{
|
||||
// passed by const reference. user can access the pointer but does not take ownership.
|
||||
printf("user: %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
}
|
||||
|
||||
void sink(CAAutoFree<char> captr)
|
||||
{
|
||||
// passed by value. sink takes ownership and frees the pointer on return.
|
||||
printf("sink: %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char * const argv[])
|
||||
{
|
||||
|
||||
CAAutoFree<char> captr(source());
|
||||
printf("main captr A %08X %08X\n", &captr, captr());
|
||||
user(captr);
|
||||
sink(captr);
|
||||
printf("main captr B %08X %08X\n", &captr, captr());
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,583 +0,0 @@
|
|||
/*
|
||||
File: CADebugMacros.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CADebugMacros_h__)
|
||||
#define __CADebugMacros_h__
|
||||
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CADebugMacros
|
||||
//=============================================================================
|
||||
|
||||
//#define CoreAudio_StopOnFailure 1
|
||||
//#define CoreAudio_TimeStampMessages 1
|
||||
//#define CoreAudio_ThreadStampMessages 1
|
||||
//#define CoreAudio_FlushDebugMessages 1
|
||||
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
#define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 }
|
||||
#define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[0]; theCString[1] = ((char*)&the4CC)[1]; theCString[2] = ((char*)&the4CC)[2]; theCString[3] = ((char*)&the4CC)[3]; theCString[4] = 0; }
|
||||
#else
|
||||
#define CA4CCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 }
|
||||
#define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[3]; theCString[1] = ((char*)&the4CC)[2]; theCString[2] = ((char*)&the4CC)[1]; theCString[3] = ((char*)&the4CC)[0]; theCString[4] = 0; }
|
||||
#endif
|
||||
|
||||
// This is a macro that does a sizeof and casts the result to a UInt32. This is useful for all the
|
||||
// places where -wshorten64-32 catches assigning a sizeof expression to a UInt32.
|
||||
// For want of a better place to park this, we'll park it here.
|
||||
#define SizeOf32(X) ((UInt32)sizeof(X))
|
||||
|
||||
// This is a macro that does a offsetof and casts the result to a UInt32. This is useful for all the
|
||||
// places where -wshorten64-32 catches assigning an offsetof expression to a UInt32.
|
||||
// For want of a better place to park this, we'll park it here.
|
||||
#define OffsetOf32(X, Y) ((UInt32)offsetof(X, Y))
|
||||
|
||||
// This macro casts the expression to a UInt32. It is called out specially to allow us to track casts
|
||||
// that have been added purely to avert -wshorten64-32 warnings on 64 bit platforms.
|
||||
// For want of a better place to park this, we'll park it here.
|
||||
#define ToUInt32(X) ((UInt32)(X))
|
||||
#define ToSInt32(X) ((SInt32)(X))
|
||||
|
||||
#pragma mark Basic Definitions
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
// can be used to break into debugger immediately, also see CADebugger
|
||||
#define BusError() { long* p=NULL; *p=0; }
|
||||
|
||||
// basic debugging print routines
|
||||
#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON
|
||||
extern void DebugStr(const unsigned char* debuggerMsg);
|
||||
#define DebugMessage(msg) DebugStr("\p"msg)
|
||||
#define DebugMessageN1(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3)
|
||||
#else
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile)
|
||||
#define FlushRtn ,fflush(DebugPrintfFile)
|
||||
#else
|
||||
#define FlushRtn
|
||||
#endif
|
||||
|
||||
#if CoreAudio_ThreadStampMessages
|
||||
#include <pthread.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#if TARGET_RT_64_BIT
|
||||
#define DebugPrintfThreadIDFormat "%16p"
|
||||
#else
|
||||
#define DebugPrintfThreadIDFormat "%8p"
|
||||
#endif
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn
|
||||
#elif CoreAudio_TimeStampMessages
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn
|
||||
#endif
|
||||
#endif
|
||||
void DebugPrint(const char *fmt, ...); // can be used like printf
|
||||
#ifndef DEBUGPRINT
|
||||
#define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h)
|
||||
#endif
|
||||
#if VERBOSE
|
||||
#define vprint(msg) DEBUGPRINT(msg)
|
||||
#else
|
||||
#define vprint(msg)
|
||||
#endif
|
||||
|
||||
// Original macro keeps its function of turning on and off use of CADebuggerStop() for both asserts and throws.
|
||||
// For backwards compat, it overrides any setting of the two sub-macros.
|
||||
#if CoreAudio_StopOnFailure
|
||||
#include "CADebugger.h"
|
||||
#undef CoreAudio_StopOnAssert
|
||||
#define CoreAudio_StopOnAssert 1
|
||||
#undef CoreAudio_StopOnThrow
|
||||
#define CoreAudio_StopOnThrow 1
|
||||
#define STOP CADebuggerStop()
|
||||
#else
|
||||
#define STOP
|
||||
#endif
|
||||
|
||||
#if CoreAudio_StopOnAssert
|
||||
#if !CoreAudio_StopOnFailure
|
||||
#include "CADebugger.h"
|
||||
#define STOP
|
||||
#endif
|
||||
#define __ASSERT_STOP CADebuggerStop()
|
||||
#else
|
||||
#define __ASSERT_STOP
|
||||
#endif
|
||||
|
||||
#if CoreAudio_StopOnThrow
|
||||
#if !CoreAudio_StopOnFailure
|
||||
#include "CADebugger.h"
|
||||
#define STOP
|
||||
#endif
|
||||
#define __THROW_STOP CADebuggerStop()
|
||||
#else
|
||||
#define __THROW_STOP
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...)
|
||||
#ifndef DEBUGPRINT
|
||||
#define DEBUGPRINT(msg)
|
||||
#endif
|
||||
#define vprint(msg)
|
||||
#define STOP
|
||||
#define __ASSERT_STOP
|
||||
#define __THROW_STOP
|
||||
#endif
|
||||
|
||||
// Old-style numbered DebugMessage calls are implemented in terms of DebugMsg() now
|
||||
#define DebugMessage(msg) DebugMsg(msg)
|
||||
#define DebugMessageN1(msg, N1) DebugMsg(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2) DebugMsg(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3) DebugMsg(msg, N1, N2, N3)
|
||||
#define DebugMessageN4(msg, N1, N2, N3, N4) DebugMsg(msg, N1, N2, N3, N4)
|
||||
#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugMsg(msg, N1, N2, N3, N4, N5)
|
||||
#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugMsg(msg, N1, N2, N3, N4, N5, N6)
|
||||
#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7)
|
||||
#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8)
|
||||
#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9)
|
||||
|
||||
void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging)
|
||||
void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging)
|
||||
|
||||
#define NO_ACTION (void)0
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#pragma mark Debug Macros
|
||||
|
||||
#define Assert(inCondition, inMessage) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
__ASSERT_STOP; \
|
||||
}
|
||||
|
||||
#define AssertFileLine(inCondition, inMessage) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
DebugMessageN3("%s, line %d: %s", __FILE__, __LINE__, inMessage); \
|
||||
__ASSERT_STOP; \
|
||||
}
|
||||
|
||||
#define AssertNoError(inError, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
char __4CC[5] = CA4CCToCString(__Err); \
|
||||
DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AssertNoKernelError(inError, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (unsigned int)(inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AssertNotNULL(inPtr, inMessage) \
|
||||
{ \
|
||||
if((inPtr) == NULL) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIf(inCondition, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailWithAction(inCondition, inAction, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIfError(inError, inAction, inHandler, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
char __4CC[5] = CA4CCToCString(__Err); \
|
||||
DebugMessageN2(inMessage ", Error: %ld (%s)", (long int)__Err, __4CC); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIfNoMessage(inCondition, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#define Throw(inException) __THROW_STOP; throw (inException)
|
||||
|
||||
#define ThrowIf(inCondition, inException, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfNULL(inPointer, inException, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfKernelError(inKernelError, inException, inMessage) \
|
||||
{ \
|
||||
int __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ThrowIfError(inError, inException, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
char __4CC[5] = CA4CCToCString(__Err); \
|
||||
DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#define ThrowIfWinError(inError, inException, inMessage) \
|
||||
{ \
|
||||
HRESULT __Err = (inError); \
|
||||
if(FAILED(__Err)) \
|
||||
{ \
|
||||
DebugMessageN2(inMessage ", Code: %d, Facility: 0x%X", HRESULT_CODE(__Err), HRESULT_FACILITY(__Err)); \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SubclassResponsibility(inMethodName, inException) \
|
||||
{ \
|
||||
DebugMessage(inMethodName": Subclasses must implement this method"); \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#endif // defined(__cplusplus)
|
||||
|
||||
#else
|
||||
|
||||
#pragma mark Release Macros
|
||||
|
||||
#define Assert(inCondition, inMessage) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
__ASSERT_STOP; \
|
||||
}
|
||||
|
||||
#define AssertFileLine(inCondition, inMessage) Assert(inCondition, inMessage)
|
||||
|
||||
#define AssertNoError(inError, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AssertNoKernelError(inError, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (unsigned int)(inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AssertNotNULL(inPtr, inMessage) \
|
||||
{ \
|
||||
if((inPtr) == NULL) \
|
||||
{ \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIf(inCondition, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailWithAction(inCondition, inAction, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \
|
||||
if((inKernelError) != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfError(inError, inAction, inHandler, inMessage) \
|
||||
if((inError) != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNoMessage(inCondition, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#define Throw(inException) __THROW_STOP; throw (inException)
|
||||
|
||||
#define ThrowIf(inCondition, inException, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfNULL(inPointer, inException, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfKernelError(inKernelError, inException, inMessage) \
|
||||
{ \
|
||||
int __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ThrowIfError(inError, inException, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#define ThrowIfWinError(inError, inException, inMessage) \
|
||||
{ \
|
||||
HRESULT __Err = (inError); \
|
||||
if(FAILED(__Err)) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SubclassResponsibility(inMethodName, inException) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#endif // defined(__cplusplus)
|
||||
|
||||
#endif // DEBUG || CoreAudio_Debug
|
||||
|
||||
#endif
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
File: CADebugPrintf.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CADebugPrintf_h__)
|
||||
#define __CADebugPrintf_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Macros to redirect debugging output to various logging services
|
||||
//=============================================================================
|
||||
|
||||
//#define CoreAudio_UseSysLog 1
|
||||
//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
extern int CAWin32DebugPrintf(char* inFormat, ...);
|
||||
#define DebugPrintfRtn CAWin32DebugPrintf
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma
|
||||
#else
|
||||
#if CoreAudio_UseSysLog
|
||||
#include <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#elif defined(CoreAudio_UseSideFile)
|
||||
#include <stdio.h>
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void OpenDebugPrintfSideFile();
|
||||
extern FILE* sDebugPrintfSideFile;
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr)
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile stderr
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DebugPrintfRtn
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding
|
||||
#define DebugPrintfFileComma
|
||||
#define DebugPrintf(inFormat, ...)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
File: CAException.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAException_h__)
|
||||
#define __CAException_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAException
|
||||
//=============================================================================
|
||||
|
||||
class CAException
|
||||
{
|
||||
|
||||
public:
|
||||
CAException(OSStatus inError) : mError(inError) {}
|
||||
CAException(const CAException& inException) : mError(inException.mError) {}
|
||||
CAException& operator=(const CAException& inException) { mError = inException.mError; return *this; }
|
||||
~CAException() {}
|
||||
|
||||
OSStatus GetError() const { return mError; }
|
||||
|
||||
protected:
|
||||
OSStatus mError;
|
||||
};
|
||||
|
||||
#define CATry try{
|
||||
#define CACatch } catch(...) {}
|
||||
#define CASwallowException(inExpression) try { inExpression; } catch(...) {}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
File: CAHostTimeBase.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAHostTimeBase_h__)
|
||||
#define __CAHostTimeBase_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include "WinPThreadDefs.h"
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
//=============================================================================
|
||||
// CAHostTimeBase
|
||||
//
|
||||
// This class provides platform independent access to the host's time base.
|
||||
//=============================================================================
|
||||
|
||||
#if CoreAudio_Debug
|
||||
// #define Log_Host_Time_Base_Parameters 1
|
||||
// #define Track_Host_TimeBase 1
|
||||
#endif
|
||||
|
||||
class CAHostTimeBase
|
||||
{
|
||||
|
||||
public:
|
||||
static UInt64 ConvertToNanos(UInt64 inHostTime);
|
||||
static UInt64 ConvertFromNanos(UInt64 inNanos);
|
||||
|
||||
static UInt64 GetTheCurrentTime();
|
||||
#if TARGET_OS_MAC
|
||||
static UInt64 GetCurrentTime() { return GetTheCurrentTime(); }
|
||||
#endif
|
||||
static UInt64 GetCurrentTimeInNanos();
|
||||
|
||||
static Float64 GetFrequency() { pthread_once(&sIsInited, Initialize); return sFrequency; }
|
||||
static Float64 GetInverseFrequency() { pthread_once(&sIsInited, Initialize); return sInverseFrequency; }
|
||||
static UInt32 GetMinimumDelta() { pthread_once(&sIsInited, Initialize); return sMinDelta; }
|
||||
|
||||
static UInt64 AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime);
|
||||
static SInt64 HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime);
|
||||
|
||||
static UInt64 MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator);
|
||||
|
||||
private:
|
||||
static void Initialize();
|
||||
|
||||
static pthread_once_t sIsInited;
|
||||
|
||||
static Float64 sFrequency;
|
||||
static Float64 sInverseFrequency;
|
||||
static UInt32 sMinDelta;
|
||||
static UInt32 sToNanosNumerator;
|
||||
static UInt32 sToNanosDenominator;
|
||||
#if Track_Host_TimeBase
|
||||
static UInt64 sLastTime;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline UInt64 CAHostTimeBase::GetTheCurrentTime()
|
||||
{
|
||||
UInt64 theTime = 0;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
theTime = mach_absolute_time();
|
||||
#elif TARGET_OS_WIN32
|
||||
LARGE_INTEGER theValue;
|
||||
QueryPerformanceCounter(&theValue);
|
||||
theTime = *((UInt64*)&theValue);
|
||||
#endif
|
||||
|
||||
#if Track_Host_TimeBase
|
||||
if(sLastTime != 0)
|
||||
{
|
||||
if(theTime <= sLastTime)
|
||||
{
|
||||
DebugPrintf("CAHostTimeBase::GetTheCurrentTime: the current time is earlier than the last time, now: %qd, then: %qd", theTime, sLastTime);
|
||||
}
|
||||
sLastTime = theTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
sLastTime = theTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
return theTime;
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::ConvertToNanos(UInt64 inHostTime)
|
||||
{
|
||||
pthread_once(&sIsInited, Initialize);
|
||||
|
||||
UInt64 theAnswer = MultiplyByRatio(inHostTime, sToNanosNumerator, sToNanosDenominator);
|
||||
#if CoreAudio_Debug
|
||||
if(((sToNanosNumerator > sToNanosDenominator) && (theAnswer < inHostTime)) || ((sToNanosDenominator > sToNanosNumerator) && (theAnswer > inHostTime)))
|
||||
{
|
||||
DebugPrintf("CAHostTimeBase::ConvertToNanos: The conversion wrapped");
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos)
|
||||
{
|
||||
pthread_once(&sIsInited, Initialize);
|
||||
|
||||
UInt64 theAnswer = MultiplyByRatio(inNanos, sToNanosDenominator, sToNanosNumerator);
|
||||
#if CoreAudio_Debug
|
||||
if(((sToNanosDenominator > sToNanosNumerator) && (theAnswer < inNanos)) || ((sToNanosNumerator > sToNanosDenominator) && (theAnswer > inNanos)))
|
||||
{
|
||||
DebugPrintf("CAHostTimeBase::ConvertFromNanos: The conversion wrapped");
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::GetCurrentTimeInNanos()
|
||||
{
|
||||
return ConvertToNanos(GetTheCurrentTime());
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime)
|
||||
{
|
||||
UInt64 theAnswer;
|
||||
|
||||
if(inStartTime <= inEndTime)
|
||||
{
|
||||
theAnswer = inEndTime - inStartTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = inStartTime - inEndTime;
|
||||
}
|
||||
|
||||
return ConvertToNanos(theAnswer);
|
||||
}
|
||||
|
||||
inline SInt64 CAHostTimeBase::HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime)
|
||||
{
|
||||
SInt64 theAnswer;
|
||||
SInt64 theSign = 1;
|
||||
|
||||
if(inStartTime <= inEndTime)
|
||||
{
|
||||
theAnswer = static_cast<SInt64>(inEndTime - inStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = static_cast<SInt64>(inStartTime - inEndTime);
|
||||
theSign = -1;
|
||||
}
|
||||
|
||||
return theSign * static_cast<SInt64>(ConvertToNanos(static_cast<UInt64>(theAnswer)));
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator)
|
||||
{
|
||||
#if TARGET_OS_MAC && TARGET_RT_64_BIT
|
||||
__uint128_t theAnswer = inMuliplicand;
|
||||
#else
|
||||
long double theAnswer = inMuliplicand;
|
||||
#endif
|
||||
if(inNumerator != inDenominator)
|
||||
{
|
||||
theAnswer *= inNumerator;
|
||||
theAnswer /= inDenominator;
|
||||
}
|
||||
return static_cast<UInt64>(theAnswer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
File: CAMath.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAMath_h__
|
||||
#define __CAMath_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
inline bool fiszero(Float64 f) { return (f == 0.); }
|
||||
inline bool fiszero(Float32 f) { return (f == 0.f); }
|
||||
|
||||
inline bool fnonzero(Float64 f) { return !fiszero(f); }
|
||||
inline bool fnonzero(Float32 f) { return !fiszero(f); }
|
||||
|
||||
inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; }
|
||||
inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; }
|
||||
|
||||
inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); }
|
||||
inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); }
|
||||
|
||||
#endif // __CAMath_h__
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
/*
|
||||
File: CAMutex.cpp
|
||||
Abstract: CAMutex.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CAMutex.h"
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
#include "CAHostTimeBase.h"
|
||||
|
||||
//==================================================================================================
|
||||
// Logging
|
||||
//==================================================================================================
|
||||
|
||||
#if CoreAudio_Debug
|
||||
// #define Log_Ownership 1
|
||||
// #define Log_Errors 1
|
||||
// #define Log_LongLatencies 1
|
||||
// #define LongLatencyThreshholdNS 1000000ULL // nanoseconds
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// CAMutex
|
||||
//==================================================================================================
|
||||
|
||||
CAMutex::CAMutex(const char* inName)
|
||||
:
|
||||
mName(inName),
|
||||
mOwner(0)
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSStatus theError = pthread_mutex_init(&mMutex, NULL);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
#elif TARGET_OS_WIN32
|
||||
mMutex = CreateMutex(NULL, false, NULL);
|
||||
ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex.");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
CAMutex::~CAMutex()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::~CAMutex: destroying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
pthread_mutex_destroy(&mMutex);
|
||||
#elif TARGET_OS_WIN32
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::~CAMutex: destroying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
if(mMutex != NULL)
|
||||
{
|
||||
CloseHandle(mMutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CAMutex::Lock()
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t theCurrentThread = pthread_self();
|
||||
if(!pthread_equal(theCurrentThread, mOwner))
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p is locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
|
||||
#if Log_LongLatencies
|
||||
UInt64 lockTryTime = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
#endif
|
||||
|
||||
OSStatus theError = pthread_mutex_lock(&mMutex);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAMutex::Lock: Could not lock the mutex");
|
||||
mOwner = theCurrentThread;
|
||||
theAnswer = true;
|
||||
|
||||
#if Log_LongLatencies
|
||||
UInt64 lockAcquireTime = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
if (lockAcquireTime - lockTryTime >= LongLatencyThresholdNS)
|
||||
DebugPrintfRtn(DebugPrintfFileComma "Thread %p took %.6fs to acquire the lock %s\n", theCurrentThread, (lockAcquireTime - lockTryTime) * 1.0e-9 /* nanos to seconds */, mName);
|
||||
#endif
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p has locked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mOwner != GetCurrentThreadId())
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu is locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
OSStatus theError = WaitForSingleObject(mMutex, INFINITE);
|
||||
ThrowIfError(theError, CAException(theError), "CAMutex::Lock: could not lock the mutex");
|
||||
mOwner = GetCurrentThreadId();
|
||||
theAnswer = true;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAMutex::Unlock()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
if(pthread_equal(pthread_self(), mOwner))
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p is unlocking %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
mOwner = 0;
|
||||
OSStatus theError = pthread_mutex_unlock(&mMutex);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p has unlocked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own");
|
||||
}
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mOwner == GetCurrentThreadId())
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
mOwner = 0;
|
||||
bool wasReleased = ReleaseMutex(mMutex);
|
||||
ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CAMutex::Try(bool& outWasLocked)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
outWasLocked = false;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t theCurrentThread = pthread_self();
|
||||
if(!pthread_equal(theCurrentThread, mOwner))
|
||||
{
|
||||
// this means the current thread doesn't already own the lock
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
|
||||
// go ahead and call trylock to see if we can lock it.
|
||||
int theError = pthread_mutex_trylock(&mMutex);
|
||||
if(theError == 0)
|
||||
{
|
||||
// return value of 0 means we successfully locked the lock
|
||||
mOwner = theCurrentThread;
|
||||
theAnswer = true;
|
||||
outWasLocked = true;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else if(theError == EBUSY)
|
||||
{
|
||||
// return value of EBUSY means that the lock was already locked by another thread
|
||||
theAnswer = false;
|
||||
outWasLocked = false;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// any other return value means something really bad happenned
|
||||
ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this means the current thread already owns the lock
|
||||
theAnswer = true;
|
||||
outWasLocked = false;
|
||||
}
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mOwner != GetCurrentThreadId())
|
||||
{
|
||||
// this means the current thread doesn't own the lock
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
// try to acquire the mutex
|
||||
OSStatus theError = WaitForSingleObject(mMutex, 0);
|
||||
if(theError == WAIT_OBJECT_0)
|
||||
{
|
||||
// this means we successfully locked the lock
|
||||
mOwner = GetCurrentThreadId();
|
||||
theAnswer = true;
|
||||
outWasLocked = true;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else if(theError == WAIT_TIMEOUT)
|
||||
{
|
||||
// this means that the lock was already locked by another thread
|
||||
theAnswer = false;
|
||||
outWasLocked = false;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// any other return value means something really bad happenned
|
||||
ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this means the current thread already owns the lock
|
||||
theAnswer = true;
|
||||
outWasLocked = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool CAMutex::IsFree() const
|
||||
{
|
||||
return mOwner == 0;
|
||||
}
|
||||
|
||||
bool CAMutex::IsOwnedByCurrentThread() const
|
||||
{
|
||||
bool theAnswer = true;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
theAnswer = pthread_equal(pthread_self(), mOwner);
|
||||
#elif TARGET_OS_WIN32
|
||||
theAnswer = (mOwner == GetCurrentThreadId());
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
|
||||
CAMutex::Unlocker::Unlocker(CAMutex& inMutex)
|
||||
: mMutex(inMutex),
|
||||
mNeedsLock(false)
|
||||
{
|
||||
Assert(mMutex.IsOwnedByCurrentThread(), "Major problem: Unlocker attempted to unlock a mutex not owned by the current thread!");
|
||||
|
||||
mMutex.Unlock();
|
||||
mNeedsLock = true;
|
||||
}
|
||||
|
||||
CAMutex::Unlocker::~Unlocker()
|
||||
{
|
||||
if(mNeedsLock)
|
||||
{
|
||||
mMutex.Lock();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
File: CAMutex.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAMutex_h__
|
||||
#define __CAMutex_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// A recursive mutex.
|
||||
//==================================================================================================
|
||||
|
||||
class CAMutex
|
||||
{
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAMutex(const char* inName);
|
||||
virtual ~CAMutex();
|
||||
|
||||
// Actions
|
||||
public:
|
||||
virtual bool Lock();
|
||||
virtual void Unlock();
|
||||
virtual bool Try(bool& outWasLocked); // returns true if lock is free, false if not
|
||||
|
||||
virtual bool IsFree() const;
|
||||
virtual bool IsOwnedByCurrentThread() const;
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
const char* mName;
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t mOwner;
|
||||
pthread_mutex_t mMutex;
|
||||
#elif TARGET_OS_WIN32
|
||||
UInt32 mOwner;
|
||||
HANDLE mMutex;
|
||||
#endif
|
||||
|
||||
// Helper class to manage taking and releasing recursively
|
||||
public:
|
||||
class Locker
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Locker(CAMutex& inMutex) : mMutex(&inMutex), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); }
|
||||
Locker(CAMutex* inMutex) : mMutex(inMutex), mNeedsRelease(false) { mNeedsRelease = (mMutex != NULL && mMutex->Lock()); }
|
||||
// in this case the mutex can be null
|
||||
~Locker() { if(mNeedsRelease) { mMutex->Unlock(); } }
|
||||
|
||||
|
||||
private:
|
||||
Locker(const Locker&);
|
||||
Locker& operator=(const Locker&);
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAMutex* mMutex;
|
||||
bool mNeedsRelease;
|
||||
|
||||
};
|
||||
|
||||
// Unlocker
|
||||
class Unlocker
|
||||
{
|
||||
public:
|
||||
Unlocker(CAMutex& inMutex);
|
||||
~Unlocker();
|
||||
|
||||
private:
|
||||
CAMutex& mMutex;
|
||||
bool mNeedsLock;
|
||||
|
||||
// Hidden definitions of copy ctor, assignment operator
|
||||
Unlocker(const Unlocker& copy); // Not implemented
|
||||
Unlocker& operator=(const Unlocker& copy); // Not implemented
|
||||
};
|
||||
|
||||
// you can use this with Try - if you take the lock in try, pass in the outWasLocked var
|
||||
class Tryer {
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Tryer (CAMutex &mutex) : mMutex(mutex), mNeedsRelease(false), mHasLock(false) { mHasLock = mMutex.Try (mNeedsRelease); }
|
||||
~Tryer () { if (mNeedsRelease) mMutex.Unlock(); }
|
||||
|
||||
bool HasLock () const { return mHasLock; }
|
||||
|
||||
private:
|
||||
Tryer(const Tryer&);
|
||||
Tryer& operator=(const Tryer&);
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAMutex & mMutex;
|
||||
bool mNeedsRelease;
|
||||
bool mHasLock;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif // __CAMutex_h__
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
File: CAReferenceCounted.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAReferenceCounted_h__
|
||||
#define __CAReferenceCounted_h__
|
||||
|
||||
#include "CAAtomic.h"
|
||||
|
||||
// base class for reference-counted objects
|
||||
class CAReferenceCounted {
|
||||
public:
|
||||
CAReferenceCounted() : mRefCount(1) {}
|
||||
|
||||
void retain() { CAAtomicIncrement32(&mRefCount); }
|
||||
|
||||
void release()
|
||||
{
|
||||
SInt32 rc = CAAtomicDecrement32(&mRefCount);
|
||||
if (rc == 0) {
|
||||
releaseObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Retainer {
|
||||
public:
|
||||
Retainer(CAReferenceCounted *obj) : mObject(obj) { mObject->retain(); }
|
||||
~Retainer() { mObject->release(); }
|
||||
|
||||
private:
|
||||
CAReferenceCounted * mObject;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual ~CAReferenceCounted() { }
|
||||
|
||||
virtual void releaseObject ()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public:
|
||||
#endif
|
||||
SInt32 GetReferenceCount() const { return mRefCount; }
|
||||
private:
|
||||
SInt32 mRefCount;
|
||||
|
||||
CAReferenceCounted(const CAReferenceCounted &a);
|
||||
CAReferenceCounted &operator=(const CAReferenceCounted &a);
|
||||
};
|
||||
|
||||
|
||||
#endif // __CAReferenceCounted_h__
|
||||
|
|
@ -1,879 +0,0 @@
|
|||
/*
|
||||
File: CAStreamBasicDescription.cpp
|
||||
Abstract: CAStreamBasicDescription.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#include "CAMath.h"
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFByteOrder.h>
|
||||
#else
|
||||
#include <CFByteOrder.h>
|
||||
#endif
|
||||
|
||||
#pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
|
||||
|
||||
char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize)
|
||||
{
|
||||
if (bufsize > 0) {
|
||||
char *p = writeLocation, *pend = writeLocation + bufsize;
|
||||
union { UInt32 i; unsigned char str[4]; } u;
|
||||
unsigned char *q = u.str;
|
||||
u.i = CFSwapInt32HostToBig(t);
|
||||
|
||||
bool hasNonPrint = false;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(isprint(*q) && *q != '\\')) {
|
||||
hasNonPrint = true;
|
||||
break;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
q = u.str;
|
||||
|
||||
if (hasNonPrint)
|
||||
p += snprintf (p, pend - p, "0x");
|
||||
else if (p < pend)
|
||||
*p++ = '\'';
|
||||
|
||||
for (int i = 0; i < 4 && p < pend; ++i) {
|
||||
if (hasNonPrint) {
|
||||
p += snprintf(p, pend - p, "%02X", *q++);
|
||||
} else {
|
||||
*p++ = *q++;
|
||||
}
|
||||
}
|
||||
if (!hasNonPrint && p < pend)
|
||||
*p++ = '\'';
|
||||
if (p >= pend) p -= 1;
|
||||
*p = '\0';
|
||||
}
|
||||
return writeLocation;
|
||||
}
|
||||
|
||||
|
||||
const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription()
|
||||
{
|
||||
memset (this, 0, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription(const AudioStreamBasicDescription &desc)
|
||||
{
|
||||
SetFrom(desc);
|
||||
}
|
||||
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID,
|
||||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
|
||||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
|
||||
UInt32 inBitsPerChannel, UInt32 inFormatFlags)
|
||||
{
|
||||
mSampleRate = inSampleRate;
|
||||
mFormatID = inFormatID;
|
||||
mBytesPerPacket = inBytesPerPacket;
|
||||
mFramesPerPacket = inFramesPerPacket;
|
||||
mBytesPerFrame = inBytesPerFrame;
|
||||
mChannelsPerFrame = inChannelsPerFrame;
|
||||
mBitsPerChannel = inBitsPerChannel;
|
||||
mFormatFlags = inFormatFlags;
|
||||
mReserved = 0;
|
||||
}
|
||||
|
||||
char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize, bool brief /*=false*/) const
|
||||
{
|
||||
int bufsize = (int)_bufsize; // must be signed to protect against overflow
|
||||
char *theBuffer = buf;
|
||||
int nc;
|
||||
char formatID[24];
|
||||
CAStringForOSType(mFormatID, formatID, sizeof(formatID));
|
||||
if (brief) {
|
||||
CommonPCMFormat com;
|
||||
bool interleaved;
|
||||
if (IdentifyCommonPCMFormat(com, &interleaved) && com != kPCMFormatOther) {
|
||||
const char *desc;
|
||||
switch (com) {
|
||||
case kPCMFormatInt16:
|
||||
desc = "Int16";
|
||||
break;
|
||||
case kPCMFormatFixed824:
|
||||
desc = "Int8.24";
|
||||
break;
|
||||
case kPCMFormatFloat32:
|
||||
desc = "Float32";
|
||||
break;
|
||||
case kPCMFormatFloat64:
|
||||
desc = "Float64";
|
||||
break;
|
||||
default:
|
||||
desc = NULL;
|
||||
break;
|
||||
}
|
||||
if (desc) {
|
||||
const char *inter ="";
|
||||
if (mChannelsPerFrame > 1)
|
||||
inter = !interleaved ? ", non-inter" : ", inter";
|
||||
snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s%s", (int)mChannelsPerFrame, mSampleRate, desc, inter);
|
||||
return theBuffer;
|
||||
}
|
||||
}
|
||||
if (mChannelsPerFrame == 0 && mSampleRate == 0.0 && mFormatID == 0) {
|
||||
snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz", (int)mChannelsPerFrame, mSampleRate);
|
||||
return theBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
nc = snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags);
|
||||
buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
if (mFormatID == kAudioFormatLinearPCM) {
|
||||
bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
|
||||
int wordSize = static_cast<int>(SampleWordSize());
|
||||
const char *endian = (wordSize > 1) ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
|
||||
const char *sign = isInt ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
|
||||
const char *floatInt = isInt ? "integer" : "float";
|
||||
char packed[32];
|
||||
if (wordSize > 0 && PackednessIsSignificant()) {
|
||||
if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
|
||||
snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize);
|
||||
else
|
||||
snprintf(packed, sizeof(packed), "unpacked in %d bytes", wordSize);
|
||||
} else
|
||||
packed[0] = '\0';
|
||||
const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
|
||||
const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
|
||||
const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
|
||||
char bitdepth[20];
|
||||
|
||||
int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
|
||||
if (fracbits > 0)
|
||||
snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits);
|
||||
else
|
||||
snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel);
|
||||
|
||||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%s-bit%s%s %s%s%s%s%s",
|
||||
bitdepth, endian, sign, floatInt,
|
||||
commaSpace, packed, align, deinter);
|
||||
// buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
} else if (mFormatID == kAudioFormatAppleLossless) {
|
||||
int sourceBits = 0;
|
||||
switch (mFormatFlags)
|
||||
{
|
||||
case 1: // kAppleLosslessFormatFlag_16BitSourceData
|
||||
sourceBits = 16;
|
||||
break;
|
||||
case 2: // kAppleLosslessFormatFlag_20BitSourceData
|
||||
sourceBits = 20;
|
||||
break;
|
||||
case 3: // kAppleLosslessFormatFlag_24BitSourceData
|
||||
sourceBits = 24;
|
||||
break;
|
||||
case 4: // kAppleLosslessFormatFlag_32BitSourceData
|
||||
sourceBits = 32;
|
||||
break;
|
||||
}
|
||||
if (sourceBits)
|
||||
nc = snprintf(buf, static_cast<size_t>(bufsize), "from %d-bit source, ", sourceBits);
|
||||
else
|
||||
nc = snprintf(buf, static_cast<size_t>(bufsize), "from UNKNOWN source bit depth, ");
|
||||
buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%d frames/packet", (int)mFramesPerPacket);
|
||||
// buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
}
|
||||
else
|
||||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame",
|
||||
(int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame);
|
||||
exit:
|
||||
return theBuffer;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the canonical linear PCM format
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagsCanonical;
|
||||
ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the canonical linear PCM format
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
|
||||
if(inNativeEndian)
|
||||
{
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_RT_LITTLE_ENDIAN
|
||||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
ioDescription.mSampleRate = 0;
|
||||
ioDescription.mFormatID = 0;
|
||||
ioDescription.mBytesPerPacket = 0;
|
||||
ioDescription.mFramesPerPacket = 0;
|
||||
ioDescription.mBytesPerFrame = 0;
|
||||
ioDescription.mChannelsPerFrame = 0;
|
||||
ioDescription.mBitsPerChannel = 0;
|
||||
ioDescription.mFormatFlags = 0;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
|
||||
{
|
||||
if(fiszero(ioDescription.mSampleRate))
|
||||
{
|
||||
ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
|
||||
}
|
||||
if(ioDescription.mFormatID == 0)
|
||||
{
|
||||
ioDescription.mFormatID = inTemplateDescription.mFormatID;
|
||||
}
|
||||
if(ioDescription.mFormatFlags == 0)
|
||||
{
|
||||
ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
|
||||
}
|
||||
if(ioDescription.mBytesPerPacket == 0)
|
||||
{
|
||||
ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
|
||||
}
|
||||
if(ioDescription.mFramesPerPacket == 0)
|
||||
{
|
||||
ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
|
||||
}
|
||||
if(ioDescription.mBytesPerFrame == 0)
|
||||
{
|
||||
ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
|
||||
}
|
||||
if(ioDescription.mChannelsPerFrame == 0)
|
||||
{
|
||||
ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
|
||||
}
|
||||
if(ioDescription.mBitsPerChannel == 0)
|
||||
{
|
||||
ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate)
|
||||
{
|
||||
if(inIncludeSampleRate)
|
||||
{
|
||||
int theCharactersWritten = snprintf(outName, inMaxNameLength, "%.0f ", inDescription.mSampleRate);
|
||||
outName += theCharactersWritten;
|
||||
inMaxNameLength -= static_cast<UInt32>(theCharactersWritten);
|
||||
}
|
||||
|
||||
switch(inDescription.mFormatID)
|
||||
{
|
||||
case kAudioFormatLinearPCM:
|
||||
{
|
||||
const char* theEndianString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
|
||||
{
|
||||
#if TARGET_RT_LITTLE_ENDIAN
|
||||
theEndianString = "Big Endian";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
theEndianString = "Little Endian";
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* theKindString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
|
||||
{
|
||||
theKindString = (inAbbreviate ? "Float" : "Floating Point");
|
||||
}
|
||||
else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
|
||||
{
|
||||
theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
|
||||
}
|
||||
else
|
||||
{
|
||||
theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
|
||||
}
|
||||
|
||||
const char* thePackingString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
|
||||
{
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
|
||||
{
|
||||
thePackingString = "High";
|
||||
}
|
||||
else
|
||||
{
|
||||
thePackingString = "Low";
|
||||
}
|
||||
}
|
||||
|
||||
const char* theMixabilityString = NULL;
|
||||
if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
|
||||
{
|
||||
theMixabilityString = "Mixable";
|
||||
}
|
||||
else
|
||||
{
|
||||
theMixabilityString = "Unmixable";
|
||||
}
|
||||
|
||||
if(inAbbreviate)
|
||||
{
|
||||
if(theEndianString != NULL)
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(theEndianString != NULL)
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioFormatAC3:
|
||||
strlcpy(outName, "AC-3", sizeof(outName));
|
||||
break;
|
||||
|
||||
case kAudioFormat60958AC3:
|
||||
strlcpy(outName, "AC-3 for SPDIF", sizeof(outName));
|
||||
break;
|
||||
|
||||
default:
|
||||
CACopy4CCToCString(outName, inDescription.mFormatID);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
#if CoreAudio_Debug
|
||||
#include "CALogMacros.h"
|
||||
|
||||
void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
|
||||
{
|
||||
PrintFloat (" Sample Rate: ", inDesc.mSampleRate);
|
||||
Print4CharCode (" Format ID: ", inDesc.mFormatID);
|
||||
PrintHex (" Format Flags: ", inDesc.mFormatFlags);
|
||||
PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket);
|
||||
PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket);
|
||||
PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame);
|
||||
PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame);
|
||||
PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
bool isDone = false;
|
||||
|
||||
// note that if either side is 0, that field is skipped
|
||||
|
||||
// format ID is the first order sort
|
||||
if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
|
||||
{
|
||||
if(x.mFormatID != y.mFormatID)
|
||||
{
|
||||
// formats are sorted numerically except that linear
|
||||
// PCM is always first
|
||||
if(x.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
theAnswer = true;
|
||||
}
|
||||
else if(y.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
theAnswer = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = x.mFormatID < y.mFormatID;
|
||||
}
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mixable is always better than non-mixable for linear PCM and should be the second order sort item
|
||||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
|
||||
{
|
||||
if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
|
||||
{
|
||||
theAnswer = true;
|
||||
isDone = true;
|
||||
}
|
||||
else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
theAnswer = false;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// floating point vs integer for linear PCM only
|
||||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
|
||||
{
|
||||
if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
|
||||
{
|
||||
// floating point is better than integer
|
||||
theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// bit depth
|
||||
if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
|
||||
{
|
||||
if(x.mBitsPerChannel != y.mBitsPerChannel)
|
||||
{
|
||||
// deeper bit depths are higher quality
|
||||
theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// sample rate
|
||||
if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
|
||||
{
|
||||
if(fnotequal(x.mSampleRate, y.mSampleRate))
|
||||
{
|
||||
// higher sample rates are higher quality
|
||||
theAnswer = x.mSampleRate < y.mSampleRate;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// number of channels
|
||||
if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
|
||||
{
|
||||
if(x.mChannelsPerFrame != y.mChannelsPerFrame)
|
||||
{
|
||||
// more channels is higher quality
|
||||
theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
|
||||
//isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::ModifyFormatFlagsForMatching(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y, UInt32& xFlags, UInt32& yFlags, bool converterOnly )
|
||||
{
|
||||
// match wildcards
|
||||
if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
|
||||
{
|
||||
// Obliterate all flags.
|
||||
xFlags = yFlags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (x.mFormatID == kAudioFormatLinearPCM) {
|
||||
// knock off the all clear flag
|
||||
xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
|
||||
yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
|
||||
|
||||
// if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
|
||||
if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
|
||||
xFlags = xFlags & ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh);
|
||||
yFlags = yFlags & ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh);
|
||||
}
|
||||
|
||||
// if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
|
||||
if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
|
||||
xFlags = xFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger);
|
||||
yFlags = yFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger);
|
||||
}
|
||||
|
||||
// if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
|
||||
if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
|
||||
{
|
||||
xFlags = xFlags & ~static_cast<UInt32>(kAudioFormatFlagIsBigEndian);
|
||||
}
|
||||
if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
|
||||
{
|
||||
yFlags = yFlags & ~static_cast<UInt32>(kAudioFormatFlagIsBigEndian);
|
||||
}
|
||||
|
||||
// if the number of channels is 1, we don't care about non-interleavedness
|
||||
if (x.mChannelsPerFrame == 1 && y.mChannelsPerFrame == 1) {
|
||||
xFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsNonInterleaved);
|
||||
yFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsNonInterleaved);
|
||||
}
|
||||
|
||||
if (converterOnly) {
|
||||
CAStreamBasicDescription cas_x = CAStreamBasicDescription(x);
|
||||
CAStreamBasicDescription cas_y = CAStreamBasicDescription(y);
|
||||
if (!cas_x.PackednessIsSignificant() && !cas_y.PackednessIsSignificant()) {
|
||||
xFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsPacked);
|
||||
yFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsPacked);
|
||||
}
|
||||
if (!cas_x.AlignmentIsSignificant() && !cas_y.AlignmentIsSignificant()) {
|
||||
xFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh);
|
||||
yFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsAlignedHigh);
|
||||
}
|
||||
// We don't care about whether the streams are mixable in this case
|
||||
xFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonMixable);
|
||||
yFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonMixable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
UInt32 xFlags = x.mFormatFlags;
|
||||
UInt32 yFlags = y.mFormatFlags;
|
||||
|
||||
CAStreamBasicDescription::ModifyFormatFlagsForMatching(x, y, xFlags, yFlags, false);
|
||||
return xFlags == yFlags;
|
||||
}
|
||||
|
||||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
// the semantics for equality are:
|
||||
// 1) Values must match exactly -- except for PCM format flags, see above.
|
||||
// 2) wildcard's are ignored in the comparison
|
||||
|
||||
#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
|
||||
|
||||
return
|
||||
// check all but the format flags
|
||||
CAStreamBasicDescription::FlagIndependentEquivalence(x, y)
|
||||
// check the format flags
|
||||
&& MatchFormatFlags(x, y);
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::FlagIndependentEquivalence(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y)
|
||||
{
|
||||
return
|
||||
// check the sample rate
|
||||
(fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
|
||||
|
||||
// check the format ids
|
||||
&& MATCH(mFormatID)
|
||||
|
||||
// check the bytes per packet
|
||||
&& MATCH(mBytesPerPacket)
|
||||
|
||||
// check the frames per packet
|
||||
&& MATCH(mFramesPerPacket)
|
||||
|
||||
// check the bytes per frame
|
||||
&& MATCH(mBytesPerFrame)
|
||||
|
||||
// check the channels per frame
|
||||
&& MATCH(mChannelsPerFrame)
|
||||
|
||||
// check the channels per frame
|
||||
&& MATCH(mBitsPerChannel) ;
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const
|
||||
{
|
||||
if (interpretingWildcards)
|
||||
return *this == other;
|
||||
return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0;
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::IsFunctionallyEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y)
|
||||
{
|
||||
UInt32 xFlags = x.mFormatFlags, yFlags = y.mFormatFlags;
|
||||
CAStreamBasicDescription::ModifyFormatFlagsForMatching(x, y, xFlags, yFlags, true);
|
||||
|
||||
return
|
||||
// check all but the format flags
|
||||
CAStreamBasicDescription::FlagIndependentEquivalence(x, y)
|
||||
// check the format flags with converter focus
|
||||
&& (xFlags == yFlags);
|
||||
|
||||
}
|
||||
|
||||
bool SanityCheck(const AudioStreamBasicDescription& x)
|
||||
{
|
||||
// This function returns false if there are sufficiently insane values in any field.
|
||||
// It is very conservative so even some very unlikely values will pass.
|
||||
// This is just meant to catch the case where the data from a file is corrupted.
|
||||
|
||||
return
|
||||
(x.mSampleRate >= 0.)
|
||||
&& (x.mSampleRate < 3e6) // SACD sample rate is 2.8224 MHz
|
||||
&& (x.mBytesPerPacket < 1000000)
|
||||
&& (x.mFramesPerPacket < 1000000)
|
||||
&& (x.mBytesPerFrame < 1000000)
|
||||
&& (x.mChannelsPerFrame <= 1024)
|
||||
&& (x.mBitsPerChannel <= 1024)
|
||||
&& (x.mFormatID != 0)
|
||||
&& !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame));
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::FromText(const char *inTextDesc, AudioStreamBasicDescription &fmt)
|
||||
{
|
||||
const char *p = inTextDesc;
|
||||
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
|
||||
bool isPCM = true; // until proven otherwise
|
||||
UInt32 pcmFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
|
||||
|
||||
if (p[0] == '-') // previously we required a leading dash on PCM formats
|
||||
++p;
|
||||
|
||||
if (p[0] == 'B' && p[1] == 'E') {
|
||||
pcmFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
p += 2;
|
||||
} else if (p[0] == 'L' && p[1] == 'E') {
|
||||
p += 2;
|
||||
} else {
|
||||
// default is native-endian
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
pcmFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
if (p[0] == 'F') {
|
||||
pcmFlags = (pcmFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger)) | kAudioFormatFlagIsFloat;
|
||||
++p;
|
||||
} else {
|
||||
if (p[0] == 'U') {
|
||||
pcmFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger);
|
||||
++p;
|
||||
}
|
||||
if (p[0] == 'I')
|
||||
++p;
|
||||
else {
|
||||
// it's not PCM; presumably some other format (NOT VALIDATED; use AudioFormat for that)
|
||||
isPCM = false;
|
||||
p = inTextDesc; // go back to the beginning
|
||||
char buf[4] = { ' ',' ',' ',' ' };
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (*p != '\\') {
|
||||
if ((buf[i] = *p++) == '\0') {
|
||||
// special-case for 'aac'
|
||||
if (i != 3) return false;
|
||||
--p; // keep pointing at the terminating null
|
||||
buf[i] = ' ';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// "\xNN" is a hex byte
|
||||
if (*++p != 'x') return false;
|
||||
int x;
|
||||
if (sscanf(++p, "%02X", &x) != 1) return false;
|
||||
buf[i] = static_cast<char>(x);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (strchr("-@/#", buf[3])) {
|
||||
// further special-casing for 'aac'
|
||||
buf[3] = ' ';
|
||||
--p;
|
||||
}
|
||||
|
||||
memcpy(&fmt.mFormatID, buf, 4);
|
||||
fmt.mFormatID = CFSwapInt32BigToHost(fmt.mFormatID);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPCM) {
|
||||
fmt.mFormatID = kAudioFormatLinearPCM;
|
||||
fmt.mFormatFlags = pcmFlags;
|
||||
fmt.mFramesPerPacket = 1;
|
||||
fmt.mChannelsPerFrame = 1;
|
||||
UInt32 bitdepth = 0, fracbits = 0;
|
||||
while (isdigit(*p))
|
||||
bitdepth = 10 * bitdepth + static_cast<UInt32>(*p++ - '0');
|
||||
if (*p == '.') {
|
||||
++p;
|
||||
if (!isdigit(*p)) {
|
||||
fprintf(stderr, "Expected fractional bits following '.'\n");
|
||||
goto Bail;
|
||||
}
|
||||
while (isdigit(*p))
|
||||
fracbits = 10 * fracbits + static_cast<UInt32>(*p++ - '0');
|
||||
bitdepth += fracbits;
|
||||
fmt.mFormatFlags |= (fracbits << kLinearPCMFormatFlagsSampleFractionShift);
|
||||
}
|
||||
fmt.mBitsPerChannel = bitdepth;
|
||||
fmt.mBytesPerPacket = fmt.mBytesPerFrame = (bitdepth + 7) / 8;
|
||||
if (bitdepth & 7) {
|
||||
// assume unpacked. (packed odd bit depths are describable but not supported in AudioConverter.)
|
||||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsPacked);
|
||||
// alignment matters; default to high-aligned. use ':L_' for low.
|
||||
fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh;
|
||||
}
|
||||
}
|
||||
if (*p == '@') {
|
||||
++p;
|
||||
while (isdigit(*p))
|
||||
fmt.mSampleRate = 10 * fmt.mSampleRate + (*p++ - '0');
|
||||
}
|
||||
if (*p == '/') {
|
||||
UInt32 flags = 0;
|
||||
while (true) {
|
||||
char c = *++p;
|
||||
if (c >= '0' && c <= '9')
|
||||
flags = (flags << 4) | static_cast<UInt32>(c - '0');
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
flags = (flags << 4) | static_cast<UInt32>(c - 'A' + 10);
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
flags = (flags << 4) | static_cast<UInt32>(c - 'a' + 10);
|
||||
else break;
|
||||
}
|
||||
fmt.mFormatFlags = flags;
|
||||
}
|
||||
if (*p == '#') {
|
||||
++p;
|
||||
while (isdigit(*p))
|
||||
fmt.mFramesPerPacket = 10 * fmt.mFramesPerPacket + static_cast<UInt32>(*p++ - '0');
|
||||
}
|
||||
if (*p == ':') {
|
||||
++p;
|
||||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsPacked);
|
||||
if (*p == 'L')
|
||||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsAlignedHigh);
|
||||
else if (*p == 'H')
|
||||
fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh;
|
||||
else
|
||||
goto Bail;
|
||||
++p;
|
||||
UInt32 bytesPerFrame = 0;
|
||||
while (isdigit(*p))
|
||||
bytesPerFrame = 10 * bytesPerFrame + static_cast<UInt32>(*p++ - '0');
|
||||
fmt.mBytesPerFrame = fmt.mBytesPerPacket = bytesPerFrame;
|
||||
}
|
||||
if (*p == ',') {
|
||||
++p;
|
||||
int ch = 0;
|
||||
while (isdigit(*p))
|
||||
ch = 10 * ch + (*p++ - '0');
|
||||
fmt.mChannelsPerFrame = static_cast<UInt32>(ch);
|
||||
if (*p == 'D') {
|
||||
++p;
|
||||
if (fmt.mFormatID != kAudioFormatLinearPCM) {
|
||||
fprintf(stderr, "non-interleaved flag invalid for non-PCM formats\n");
|
||||
goto Bail;
|
||||
}
|
||||
fmt.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
} else {
|
||||
if (*p == 'I') ++p; // default
|
||||
if (fmt.mFormatID == kAudioFormatLinearPCM)
|
||||
fmt.mBytesPerPacket = fmt.mBytesPerFrame *= static_cast<UInt32>(ch);
|
||||
}
|
||||
}
|
||||
if (*p != '\0') {
|
||||
fprintf(stderr, "extra characters at end of format string: %s\n", p);
|
||||
goto Bail;
|
||||
}
|
||||
return true;
|
||||
|
||||
Bail:
|
||||
fprintf(stderr, "Invalid format string: %s\n", inTextDesc);
|
||||
fprintf(stderr, "Syntax of format strings is: \n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *CAStreamBasicDescription::sTextParsingUsageString =
|
||||
"format[@sample_rate_hz][/format_flags][#frames_per_packet][:LHbytesPerFrame][,channelsDI].\n"
|
||||
"Format for PCM is [-][BE|LE]{F|I|UI}{bitdepth}; else a 4-char format code (e.g. aac, alac).\n";
|
||||
|
|
@ -1,424 +0,0 @@
|
|||
/*
|
||||
File: CAStreamBasicDescription.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAStreamBasicDescription_h__
|
||||
#define __CAStreamBasicDescription_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#include "CoreFoundation.h"
|
||||
#endif
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include <string.h> // for memset, memcpy
|
||||
#include <stdio.h> // for FILE *
|
||||
|
||||
#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it
|
||||
|
||||
extern char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize);
|
||||
|
||||
// define Leopard specific symbols for backward compatibility if applicable
|
||||
#if COREAUDIOTYPES_VERSION < 1050
|
||||
typedef Float32 AudioSampleType;
|
||||
enum { kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked };
|
||||
#endif
|
||||
#if COREAUDIOTYPES_VERSION < 1051
|
||||
typedef Float32 AudioUnitSampleType;
|
||||
enum {
|
||||
kLinearPCMFormatFlagsSampleFractionShift = 7,
|
||||
kLinearPCMFormatFlagsSampleFractionMask = (0x3F << kLinearPCMFormatFlagsSampleFractionShift),
|
||||
};
|
||||
#endif
|
||||
|
||||
// define the IsMixable format flag for all versions of the system
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3)
|
||||
enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable };
|
||||
#else
|
||||
enum { kIsNonMixableFlag = (1L << 6) };
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAStreamBasicDescription
|
||||
//
|
||||
// This is a wrapper class for the AudioStreamBasicDescription struct.
|
||||
// It adds a number of convenience routines, but otherwise adds nothing
|
||||
// to the footprint of the original struct.
|
||||
//=============================================================================
|
||||
class CAStreamBasicDescription :
|
||||
public AudioStreamBasicDescription
|
||||
{
|
||||
|
||||
// Constants
|
||||
public:
|
||||
static const AudioStreamBasicDescription sEmpty;
|
||||
|
||||
enum CommonPCMFormat {
|
||||
kPCMFormatOther = 0,
|
||||
kPCMFormatFloat32 = 1,
|
||||
kPCMFormatInt16 = 2,
|
||||
kPCMFormatFixed824 = 3,
|
||||
kPCMFormatFloat64 = 4
|
||||
};
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAStreamBasicDescription();
|
||||
|
||||
CAStreamBasicDescription(const AudioStreamBasicDescription &desc);
|
||||
|
||||
CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID,
|
||||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
|
||||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
|
||||
UInt32 inBitsPerChannel, UInt32 inFormatFlags);
|
||||
|
||||
CAStreamBasicDescription( double inSampleRate, UInt32 inNumChannels, CommonPCMFormat pcmf, bool inIsInterleaved) {
|
||||
unsigned wordsize;
|
||||
|
||||
mSampleRate = inSampleRate;
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
mFramesPerPacket = 1;
|
||||
mChannelsPerFrame = inNumChannels;
|
||||
mBytesPerFrame = mBytesPerPacket = 0;
|
||||
mReserved = 0;
|
||||
|
||||
switch (pcmf) {
|
||||
default:
|
||||
return;
|
||||
case kPCMFormatFloat32:
|
||||
wordsize = 4;
|
||||
mFormatFlags |= kAudioFormatFlagIsFloat;
|
||||
break;
|
||||
case kPCMFormatFloat64:
|
||||
wordsize = 8;
|
||||
mFormatFlags |= kAudioFormatFlagIsFloat;
|
||||
break;
|
||||
case kPCMFormatInt16:
|
||||
wordsize = 2;
|
||||
mFormatFlags |= kAudioFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case kPCMFormatFixed824:
|
||||
wordsize = 4;
|
||||
mFormatFlags |= kAudioFormatFlagIsSignedInteger | (24 << kLinearPCMFormatFlagsSampleFractionShift);
|
||||
break;
|
||||
}
|
||||
mBitsPerChannel = wordsize * 8;
|
||||
if (inIsInterleaved)
|
||||
mBytesPerFrame = mBytesPerPacket = wordsize * inNumChannels;
|
||||
else {
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
mBytesPerFrame = mBytesPerPacket = wordsize;
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment
|
||||
CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; }
|
||||
|
||||
void SetFrom(const AudioStreamBasicDescription &desc)
|
||||
{
|
||||
memcpy(this, &desc, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
bool FromText(const char *inTextDesc) { return FromText(inTextDesc, *this); }
|
||||
static bool FromText(const char *inTextDesc, AudioStreamBasicDescription &outDesc);
|
||||
// return true if parsing was successful
|
||||
|
||||
static const char *sTextParsingUsageString;
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// interrogation
|
||||
|
||||
bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; }
|
||||
|
||||
bool PackednessIsSignificant() const
|
||||
{
|
||||
Assert(IsPCM(), "PackednessIsSignificant only applies for PCM");
|
||||
return (SampleWordSize() << 3) != mBitsPerChannel;
|
||||
}
|
||||
|
||||
bool AlignmentIsSignificant() const
|
||||
{
|
||||
return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0;
|
||||
}
|
||||
|
||||
bool IsInterleaved() const
|
||||
{
|
||||
return !(mFormatFlags & kAudioFormatFlagIsNonInterleaved);
|
||||
}
|
||||
|
||||
bool IsSignedInteger() const
|
||||
{
|
||||
return IsPCM() && (mFormatFlags & kAudioFormatFlagIsSignedInteger);
|
||||
}
|
||||
|
||||
bool IsFloat() const
|
||||
{
|
||||
return IsPCM() && (mFormatFlags & kAudioFormatFlagIsFloat);
|
||||
}
|
||||
|
||||
bool IsNativeEndian() const
|
||||
{
|
||||
return (mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian;
|
||||
}
|
||||
|
||||
// for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these:
|
||||
UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; }
|
||||
UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; }
|
||||
UInt32 NumberChannels() const { return mChannelsPerFrame; }
|
||||
UInt32 SampleWordSize() const {
|
||||
return (mBytesPerFrame > 0 && NumberInterleavedChannels()) ? mBytesPerFrame / NumberInterleavedChannels() : 0;
|
||||
}
|
||||
|
||||
UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; }
|
||||
UInt32 BytesToFrames(UInt32 nbytes) const {
|
||||
Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames");
|
||||
return nbytes / mBytesPerFrame;
|
||||
}
|
||||
|
||||
bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const
|
||||
{
|
||||
return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved();
|
||||
}
|
||||
|
||||
bool IdentifyCommonPCMFormat(CommonPCMFormat &outFormat, bool *outIsInterleaved=NULL) const
|
||||
{ // return true if it's a valid PCM format.
|
||||
|
||||
outFormat = kPCMFormatOther;
|
||||
// trap out patently invalid formats.
|
||||
if (mFormatID != kAudioFormatLinearPCM || mFramesPerPacket != 1 || mBytesPerFrame != mBytesPerPacket || mBitsPerChannel/8 > mBytesPerFrame || mChannelsPerFrame == 0)
|
||||
return false;
|
||||
bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
|
||||
if (outIsInterleaved != NULL) *outIsInterleaved = interleaved;
|
||||
unsigned wordsize = mBytesPerFrame;
|
||||
if (interleaved) {
|
||||
if (wordsize % mChannelsPerFrame != 0) return false;
|
||||
wordsize /= mChannelsPerFrame;
|
||||
}
|
||||
|
||||
if ((mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian
|
||||
&& wordsize * 8 == mBitsPerChannel) {
|
||||
// packed and native endian, good
|
||||
if (mFormatFlags & kLinearPCMFormatFlagIsFloat) {
|
||||
// float: reject nonsense bits
|
||||
if (mFormatFlags & (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagsSampleFractionMask))
|
||||
return false;
|
||||
if (wordsize == 4)
|
||||
outFormat = kPCMFormatFloat32;
|
||||
if (wordsize == 8)
|
||||
outFormat = kPCMFormatFloat64;
|
||||
} else if (mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) {
|
||||
// signed int
|
||||
unsigned fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
|
||||
if (wordsize == 4 && fracbits == 24)
|
||||
outFormat = kPCMFormatFixed824;
|
||||
else if (wordsize == 2 && fracbits == 0)
|
||||
outFormat = kPCMFormatInt16;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsCommonFloat32(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat32;
|
||||
}
|
||||
bool IsCommonFloat64(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat64;
|
||||
}
|
||||
bool IsCommonFixed824(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFixed824;
|
||||
}
|
||||
bool IsCommonInt16(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatInt16;
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// manipulation
|
||||
|
||||
void SetCanonical(UInt32 nChannels, bool interleaved)
|
||||
// note: leaves sample rate untouched
|
||||
{
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
UInt32 sampleSize = SizeOf32(AudioSampleType);
|
||||
mFormatFlags = kAudioFormatFlagsCanonical;
|
||||
mBitsPerChannel = 8 * sampleSize;
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
if (interleaved)
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * sampleSize;
|
||||
else {
|
||||
mBytesPerPacket = mBytesPerFrame = sampleSize;
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCanonical() const
|
||||
{
|
||||
if (mFormatID != kAudioFormatLinearPCM) return false;
|
||||
UInt32 reqFormatFlags;
|
||||
UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagsSampleFractionMask);
|
||||
bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
|
||||
unsigned sampleSize = SizeOf32(AudioSampleType);
|
||||
reqFormatFlags = kAudioFormatFlagsCanonical;
|
||||
UInt32 reqFrameSize = interleaved ? (mChannelsPerFrame * sampleSize) : sampleSize;
|
||||
|
||||
return ((mFormatFlags & flagsMask) == reqFormatFlags
|
||||
&& mBitsPerChannel == 8 * sampleSize
|
||||
&& mFramesPerPacket == 1
|
||||
&& mBytesPerFrame == reqFrameSize
|
||||
&& mBytesPerPacket == reqFrameSize);
|
||||
}
|
||||
|
||||
void SetAUCanonical(UInt32 nChannels, bool interleaved)
|
||||
{
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
#if CA_PREFER_FIXED_POINT
|
||||
mFormatFlags = kAudioFormatFlagsCanonical | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift);
|
||||
#else
|
||||
mFormatFlags = kAudioFormatFlagsCanonical;
|
||||
#endif
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
mBitsPerChannel = 8 * SizeOf32(AudioUnitSampleType);
|
||||
if (interleaved)
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * SizeOf32(AudioUnitSampleType);
|
||||
else {
|
||||
mBytesPerPacket = mBytesPerFrame = SizeOf32(AudioUnitSampleType);
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeNumberChannels(UInt32 nChannels, bool interleaved)
|
||||
// alter an existing format
|
||||
{
|
||||
Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats");
|
||||
UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING
|
||||
if (wordSize == 0)
|
||||
wordSize = (mBitsPerChannel + 7) / 8;
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
if (interleaved) {
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * wordSize;
|
||||
mFormatFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonInterleaved);
|
||||
} else {
|
||||
mBytesPerPacket = mBytesPerFrame = wordSize;
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// other
|
||||
|
||||
bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards=true) const;
|
||||
static bool FlagIndependentEquivalence(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y);
|
||||
static bool IsFunctionallyEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y);
|
||||
|
||||
void Print() const {
|
||||
Print (stdout);
|
||||
}
|
||||
|
||||
void Print(FILE* file) const {
|
||||
PrintFormat (file, "", "AudioStreamBasicDescription:");
|
||||
}
|
||||
|
||||
void PrintFormat(FILE *f, const char *indent, const char *name) const {
|
||||
char buf[256];
|
||||
fprintf(f, "%s%s %s\n", indent, name, AsString(buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
void PrintFormat2(FILE *f, const char *indent, const char *name) const { // no trailing newline
|
||||
char buf[256];
|
||||
fprintf(f, "%s%s %s", indent, name, AsString(buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
char * AsString(char *buf, size_t bufsize, bool brief=false) const;
|
||||
|
||||
static void Print (const AudioStreamBasicDescription &inDesc)
|
||||
{
|
||||
CAStreamBasicDescription desc(inDesc);
|
||||
desc.Print ();
|
||||
}
|
||||
|
||||
OSStatus Save(CFPropertyListRef *outData) const;
|
||||
|
||||
OSStatus Restore(CFPropertyListRef &inData);
|
||||
|
||||
// Operations
|
||||
static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); }
|
||||
static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription);
|
||||
static void NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription);
|
||||
static void ResetFormat(AudioStreamBasicDescription& ioDescription);
|
||||
static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription);
|
||||
static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate = false);
|
||||
static void ModifyFormatFlagsForMatching(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y, UInt32& xFlags, UInt32& yFlags, bool converterOnly);
|
||||
|
||||
#if CoreAudio_Debug
|
||||
static void PrintToLog(const AudioStreamBasicDescription& inDesc);
|
||||
#endif
|
||||
};
|
||||
|
||||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
|
||||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
|
||||
#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600))
|
||||
inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); }
|
||||
inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); }
|
||||
inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); }
|
||||
inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); }
|
||||
#endif
|
||||
|
||||
bool SanityCheck(const AudioStreamBasicDescription& x);
|
||||
|
||||
|
||||
#endif // __CAStreamBasicDescription_h__
|
||||
|
|
@ -1,233 +0,0 @@
|
|||
/*
|
||||
File: CAThreadSafeList.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAThreadSafeList_h__
|
||||
#define __CAThreadSafeList_h__
|
||||
|
||||
#include "CAAtomicStack.h"
|
||||
|
||||
// linked list of T's
|
||||
// T must define operator ==
|
||||
template <class T>
|
||||
class TThreadSafeList {
|
||||
private:
|
||||
enum EEventType { kAdd, kRemove, kClear };
|
||||
class Node {
|
||||
public:
|
||||
Node * mNext;
|
||||
EEventType mEventType;
|
||||
T mObject;
|
||||
|
||||
Node *& next() { return mNext; }
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator {
|
||||
public:
|
||||
iterator() { }
|
||||
iterator(Node *n) : mNode(n) { }
|
||||
|
||||
bool operator == (const iterator &other) const { return this->mNode == other.mNode; }
|
||||
bool operator != (const iterator &other) const { return this->mNode != other.mNode; }
|
||||
|
||||
T & operator * () const { return mNode->mObject; }
|
||||
|
||||
iterator & operator ++ () { mNode = mNode->next(); return *this; } // preincrement
|
||||
iterator operator ++ (int) { iterator tmp = *this; mNode = mNode->next(); return tmp; } // postincrement
|
||||
|
||||
private:
|
||||
Node * mNode;
|
||||
};
|
||||
|
||||
TThreadSafeList() { }
|
||||
~TThreadSafeList()
|
||||
{
|
||||
mActiveList.free_all();
|
||||
mPendingList.free_all();
|
||||
mFreeList.free_all();
|
||||
}
|
||||
|
||||
// These may be called on any thread
|
||||
|
||||
void deferred_add(const T &obj) // can be called on any thread
|
||||
{
|
||||
Node *node = AllocNode();
|
||||
node->mEventType = kAdd;
|
||||
node->mObject = obj;
|
||||
mPendingList.push_atomic(node);
|
||||
//mPendingList.dump("pending after add");
|
||||
}
|
||||
|
||||
void deferred_remove(const T &obj) // can be called on any thread
|
||||
{
|
||||
Node *node = AllocNode();
|
||||
node->mEventType = kRemove;
|
||||
node->mObject = obj;
|
||||
mPendingList.push_atomic(node);
|
||||
//mPendingList.dump("pending after remove");
|
||||
}
|
||||
|
||||
void deferred_clear() // can be called on any thread
|
||||
{
|
||||
Node *node = AllocNode();
|
||||
node->mEventType = kClear;
|
||||
mPendingList.push_atomic(node);
|
||||
}
|
||||
|
||||
// These must be called from only one thread
|
||||
|
||||
void update() // must only be called from one thread
|
||||
{
|
||||
NodeStack reversed;
|
||||
Node *event, *node, *next;
|
||||
bool workDone = false;
|
||||
|
||||
// reverse the events so they are in order
|
||||
event = mPendingList.pop_all();
|
||||
while (event != NULL) {
|
||||
next = event->mNext;
|
||||
reversed.push_NA(event);
|
||||
event = next;
|
||||
workDone = true;
|
||||
}
|
||||
if (workDone) {
|
||||
//reversed.dump("pending popped");
|
||||
//mActiveList.dump("active before update");
|
||||
|
||||
// now process them
|
||||
while ((event = reversed.pop_NA()) != NULL) {
|
||||
switch (event->mEventType) {
|
||||
case kAdd:
|
||||
{
|
||||
Node **pnode;
|
||||
bool needToInsert = true;
|
||||
for (pnode = mActiveList.phead(); *pnode != NULL; pnode = &node->mNext) {
|
||||
node = *pnode;
|
||||
if (node->mObject == event->mObject) {
|
||||
//printf("already active!!!\n");
|
||||
FreeNode(event);
|
||||
needToInsert = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needToInsert) {
|
||||
// link the new event in at the end of the active list
|
||||
*pnode = event;
|
||||
event->mNext = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kRemove:
|
||||
// find matching node in the active list, remove it
|
||||
for (Node **pnode = mActiveList.phead(); *pnode != NULL; ) {
|
||||
node = *pnode;
|
||||
if (node->mObject == event->mObject) {
|
||||
*pnode = node->mNext; // remove from linked list
|
||||
FreeNode(node);
|
||||
break;
|
||||
}
|
||||
pnode = &node->mNext;
|
||||
}
|
||||
// dispose the request node
|
||||
FreeNode(event);
|
||||
break;
|
||||
case kClear:
|
||||
for (node = mActiveList.head(); node != NULL; ) {
|
||||
next = node->mNext;
|
||||
FreeNode(node);
|
||||
node = next;
|
||||
}
|
||||
FreeNode(event);
|
||||
break;
|
||||
default:
|
||||
//printf("invalid node type %d!\n", event->mEventType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//mActiveList.dump("active after update");
|
||||
}
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
//mActiveList.dump("active at begin");
|
||||
return iterator(mActiveList.head());
|
||||
}
|
||||
iterator end() const { return iterator(NULL); }
|
||||
|
||||
|
||||
private:
|
||||
Node * AllocNode()
|
||||
{
|
||||
Node *node = mFreeList.pop_atomic();
|
||||
if (node == NULL)
|
||||
node = (Node *)CA_malloc(sizeof(Node));
|
||||
return node;
|
||||
}
|
||||
|
||||
void FreeNode(Node *node)
|
||||
{
|
||||
mFreeList.push_atomic(node);
|
||||
}
|
||||
|
||||
private:
|
||||
class NodeStack : public TAtomicStack<Node> {
|
||||
public:
|
||||
void free_all() {
|
||||
Node *node;
|
||||
while ((node = this->pop_NA()) != NULL)
|
||||
free(node);
|
||||
}
|
||||
|
||||
Node ** phead() { return &this->mHead; }
|
||||
Node * head() const { return this->mHead; }
|
||||
};
|
||||
|
||||
NodeStack mActiveList; // what's actually in the container - only accessed on one thread
|
||||
NodeStack mPendingList; // add or remove requests - threadsafe
|
||||
NodeStack mFreeList; // free nodes for reuse - threadsafe
|
||||
};
|
||||
|
||||
#endif // __CAThreadSafeList_h__
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
File: CAVectorUnit.cpp
|
||||
Abstract: CAVectorUnit.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "CAVectorUnit.h"
|
||||
|
||||
#if !TARGET_OS_WIN32
|
||||
#include <sys/sysctl.h>
|
||||
#elif HAS_IPP
|
||||
#include "ippdefs.h"
|
||||
#include "ippcore.h"
|
||||
#endif
|
||||
|
||||
int gCAVectorUnitType = kVecUninitialized;
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
// Use cpuid to check if SSE2 is available.
|
||||
// Before calling this function make sure cpuid is available
|
||||
static SInt32 IsSSE2Available()
|
||||
{
|
||||
int return_value;
|
||||
|
||||
{
|
||||
int r_edx;
|
||||
_asm
|
||||
{
|
||||
mov eax, 0x01
|
||||
cpuid
|
||||
mov r_edx, edx
|
||||
}
|
||||
return_value = (r_edx >> 26) & 0x1;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Use cpuid to check if SSE3 is available.
|
||||
// Before calling this function make sure cpuid is available
|
||||
static SInt32 IsSSE3Available()
|
||||
{
|
||||
SInt32 return_value;
|
||||
|
||||
{
|
||||
SInt32 r_ecx;
|
||||
_asm
|
||||
{
|
||||
mov eax, 0x01
|
||||
cpuid
|
||||
mov r_ecx, ecx
|
||||
}
|
||||
return_value = r_ecx & 0x1;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Return true if the cpuid instruction is available.
|
||||
// The cpuid instruction is available if bit 21 in the EFLAGS register can be changed
|
||||
// This function may not work on Intel CPUs prior to Pentium (didn't test)
|
||||
static bool IsCpuidAvailable()
|
||||
{
|
||||
SInt32 return_value = 0x0;
|
||||
_asm{
|
||||
pushfd ; //push original EFLAGS
|
||||
pop eax ; //get original EFLAGS
|
||||
mov ecx, eax ; //save original EFLAGS
|
||||
xor eax, 200000h ; //flip ID bit in EFLAGS
|
||||
push eax ; //save new EFLAGS value on stack
|
||||
popfd ; //replace current EFLAGS value
|
||||
pushfd ; //get new EFLAGS
|
||||
pop eax ; //store new EFLAGS in EAX
|
||||
xor eax, ecx ;
|
||||
je end_cpuid_identify ; //can't toggle ID bit
|
||||
mov return_value, 0x1;
|
||||
end_cpuid_identify:
|
||||
nop;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SInt32 CAVectorUnit_Examine()
|
||||
{
|
||||
int result = kVecNone;
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#if HAS_IPP
|
||||
// Initialize the static IPP library! This needs to be done before
|
||||
// any IPP function calls, otherwise we may have a performance penalty
|
||||
int status = ippStaticInit();
|
||||
if ( status == ippStsNonIntelCpu )
|
||||
{
|
||||
IppCpuType cpuType = ippGetCpuType();
|
||||
if ( cpuType >= ippCpuSSE || cpuType <= ippCpuSSE42 )
|
||||
ippStaticInitCpu( cpuType );
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// On Windows we use cpuid to detect the vector unit because it works on Intel and AMD.
|
||||
// The IPP library does not detect SSE on AMD processors.
|
||||
if (IsCpuidAvailable())
|
||||
{
|
||||
if(IsSSE3Available())
|
||||
{
|
||||
result = kVecSSE3;
|
||||
}
|
||||
else if(IsSSE2Available())
|
||||
{
|
||||
result = kVecSSE2;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif TARGET_OS_MAC
|
||||
#if DEBUG
|
||||
if (getenv("CA_NoVector")) {
|
||||
fprintf(stderr, "CA_NoVector set; Vector unit optimized routines will be bypassed\n");
|
||||
return result;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if (TARGET_CPU_PPC || TARGET_CPU_PPC64)
|
||||
int sels[2] = { CTL_HW, HW_VECTORUNIT };
|
||||
int vType = 0; //0 == scalar only
|
||||
size_t length = sizeof(vType);
|
||||
int error = sysctl(sels, 2, &vType, &length, NULL, 0);
|
||||
if (!error && vType > 0)
|
||||
result = kVecAltivec;
|
||||
#elif (TARGET_CPU_X86 || TARGET_CPU_X86_64)
|
||||
static const struct { const char* kName; const int kVectype; } kStringVectypes[] = {
|
||||
{ "hw.optional.avx1_0", kVecAVX1 }, { "hw.optional.sse3", kVecSSE3 }, { "hw.optional.sse2", kVecSSE2 }
|
||||
};
|
||||
static const size_t kNumStringVectypes = sizeof(kStringVectypes)/sizeof(kStringVectypes[0]);
|
||||
int i = 0, answer = 0;
|
||||
while(i != kNumStringVectypes)
|
||||
{
|
||||
size_t length = sizeof(answer);
|
||||
int error = sysctlbyname(kStringVectypes[i].kName, &answer, &length, NULL, 0);
|
||||
if (!error && answer)
|
||||
{
|
||||
result = kStringVectypes[i].kVectype;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
};
|
||||
#elif CA_ARM_NEON
|
||||
result = kVecNeon;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
gCAVectorUnitType = result;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
File: CAVectorUnit.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAVectorUnit_h__
|
||||
#define __CAVectorUnit_h__
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
#include "CAVectorUnitTypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#else
|
||||
#include "CFBase.h"
|
||||
#endif
|
||||
|
||||
// Unify checks for vector units.
|
||||
// Allow setting an environment variable "CA_NoVector" to turn off vectorized code at runtime (very useful for performance testing).
|
||||
|
||||
extern int gCAVectorUnitType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern SInt32 CAVectorUnit_Examine(); // expensive. use GetType() for lazy initialization and caching.
|
||||
|
||||
static inline SInt32 CAVectorUnit_GetType()
|
||||
{
|
||||
int x = gCAVectorUnitType;
|
||||
return (x != kVecUninitialized) ? x : CAVectorUnit_Examine();
|
||||
}
|
||||
|
||||
static inline Boolean CAVectorUnit_HasVectorUnit()
|
||||
{
|
||||
return CAVectorUnit_GetType() > kVecNone;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class CAVectorUnit {
|
||||
public:
|
||||
static SInt32 GetVectorUnitType() { return CAVectorUnit_GetType(); }
|
||||
static bool HasVectorUnit() { return GetVectorUnitType() > kVecNone; }
|
||||
static bool HasAltivec() { return GetVectorUnitType() == kVecAltivec; }
|
||||
static bool HasSSE2() { return GetVectorUnitType() >= kVecSSE2; }
|
||||
static bool HasSSE3() { return GetVectorUnitType() >= kVecSSE3; }
|
||||
static bool HasAVX1() { return GetVectorUnitType() >= kVecAVX1; }
|
||||
static bool HasNeon() { return GetVectorUnitType() == kVecNeon; }
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // __CAVectorUnit_h__
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
File: CAVectorUnitTypes.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAVectorUnitTypes_h__
|
||||
#define __CAVectorUnitTypes_h__
|
||||
|
||||
enum {
|
||||
kVecUninitialized = -1,
|
||||
kVecNone = 0,
|
||||
kVecAltivec = 1,
|
||||
kVecSSE2 = 100,
|
||||
kVecSSE3 = 101,
|
||||
kVecAVX1 = 110,
|
||||
kVecNeon = 200
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,361 +0,0 @@
|
|||
/*
|
||||
File: CAXException.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAXException_h__
|
||||
#define __CAXException_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <ConditionalMacros.h>
|
||||
#include <CoreFoundation.h>
|
||||
#endif
|
||||
#include "CADebugMacros.h"
|
||||
#include <ctype.h>
|
||||
//#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
class CAX4CCString {
|
||||
public:
|
||||
CAX4CCString(OSStatus error) {
|
||||
// see if it appears to be a 4-char-code
|
||||
UInt32 beErr = CFSwapInt32HostToBig(error);
|
||||
char *str = mStr;
|
||||
memcpy(str + 1, &beErr, 4);
|
||||
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
|
||||
str[0] = str[5] = '\'';
|
||||
str[6] = '\0';
|
||||
} else if (error > -200000 && error < 200000)
|
||||
// no, format it as an integer
|
||||
snprintf(str, sizeof(mStr), "%d", (int)error);
|
||||
else
|
||||
snprintf(str, sizeof(mStr), "0x%x", (int)error);
|
||||
}
|
||||
const char *get() const { return mStr; }
|
||||
operator const char *() const { return mStr; }
|
||||
private:
|
||||
char mStr[16];
|
||||
};
|
||||
|
||||
class CAX4CCStringNoQuote {
|
||||
public:
|
||||
CAX4CCStringNoQuote(OSStatus error) {
|
||||
// see if it appears to be a 4-char-code
|
||||
UInt32 beErr = CFSwapInt32HostToBig(error);
|
||||
char *str = mStr;
|
||||
memcpy(str, &beErr, 4);
|
||||
if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) {
|
||||
str[4] = '\0';
|
||||
} else if (error > -200000 && error < 200000)
|
||||
// no, format it as an integer
|
||||
snprintf(str, sizeof(mStr), "%d", (int)error);
|
||||
else
|
||||
snprintf(str, sizeof(mStr), "0x%x", (int)error);
|
||||
}
|
||||
const char *get() const { return mStr; }
|
||||
operator const char *() const { return mStr; }
|
||||
private:
|
||||
char mStr[16];
|
||||
};
|
||||
|
||||
|
||||
// An extended exception class that includes the name of the failed operation
|
||||
class CAXException {
|
||||
public:
|
||||
CAXException(const char *operation, OSStatus err) :
|
||||
mError(err)
|
||||
{
|
||||
if (operation == NULL)
|
||||
mOperation[0] = '\0';
|
||||
else if (strlen(operation) >= sizeof(mOperation)) {
|
||||
memcpy(mOperation, operation, sizeof(mOperation) - 1);
|
||||
mOperation[sizeof(mOperation) - 1] = '\0';
|
||||
} else
|
||||
|
||||
strlcpy(mOperation, operation, sizeof(mOperation));
|
||||
}
|
||||
|
||||
char *FormatError(char *str, size_t strsize) const
|
||||
{
|
||||
return FormatError(str, strsize, mError);
|
||||
}
|
||||
|
||||
char mOperation[256];
|
||||
const OSStatus mError;
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
typedef void (*WarningHandler)(const char *msg, OSStatus err);
|
||||
|
||||
static char *FormatError(char *str, size_t strsize, OSStatus error)
|
||||
{
|
||||
strlcpy(str, CAX4CCString(error), strsize);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void Warning(const char *s, OSStatus error)
|
||||
{
|
||||
if (sWarningHandler)
|
||||
(*sWarningHandler)(s, error);
|
||||
}
|
||||
|
||||
static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; }
|
||||
private:
|
||||
static WarningHandler sWarningHandler;
|
||||
};
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
#define XThrowIfError(error, operation) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\
|
||||
__THROW_STOP; \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XThrowIf(condition, error, operation) \
|
||||
do { \
|
||||
if (condition) { \
|
||||
OSStatus __err = error; \
|
||||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\
|
||||
__THROW_STOP; \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XRequireNoError(error, label) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\
|
||||
STOP; \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssert(assertion) \
|
||||
do { \
|
||||
if (!(assertion)) { \
|
||||
DebugMessageN3("%s:%d: error: failed assertion: %s", __FILE__, __LINE__, #assertion); \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssertNoError(error) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
DebugMessageN4("%s:%d: error %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\
|
||||
STOP; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ca_require_noerr(errorCode, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
int evalOnceErrorCode = (errorCode); \
|
||||
if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
|
||||
{ \
|
||||
DebugMessageN5("ca_require_noerr: [%s, %d] (goto %s;) %s:%d", \
|
||||
#errorCode, evalOnceErrorCode, \
|
||||
#exceptionLabel, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_verify_noerr(errorCode) \
|
||||
do \
|
||||
{ \
|
||||
int evalOnceErrorCode = (errorCode); \
|
||||
if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
|
||||
{ \
|
||||
DebugMessageN4("ca_verify_noerr: [%s, %d] %s:%d", \
|
||||
#errorCode, evalOnceErrorCode, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_debug_string(message) \
|
||||
do \
|
||||
{ \
|
||||
DebugMessageN3("ca_debug_string: %s %s:%d", \
|
||||
message, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#define ca_verify(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
DebugMessageN3("ca_verify: %s %s:%d", \
|
||||
#assertion, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_require(assertion, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
DebugMessageN4("ca_require: %s %s %s:%d", \
|
||||
#assertion, \
|
||||
#exceptionLabel, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_check(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
DebugMessageN3("ca_check: %s %s:%d", \
|
||||
#assertion, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#else
|
||||
#define XThrowIfError(error, operation) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XThrowIf(condition, error, operation) \
|
||||
do { \
|
||||
if (condition) { \
|
||||
OSStatus __err = error; \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XRequireNoError(error, label) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssert(assertion) \
|
||||
do { \
|
||||
if (!(assertion)) { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssertNoError(error) \
|
||||
do { \
|
||||
/*OSStatus __err =*/ error; \
|
||||
} while (0)
|
||||
|
||||
#define ca_require_noerr(errorCode, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(0 != (errorCode), 0) ) \
|
||||
{ \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_verify_noerr(errorCode) \
|
||||
do \
|
||||
{ \
|
||||
if ( 0 != (errorCode) ) \
|
||||
{ \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_debug_string(message)
|
||||
|
||||
#define ca_verify(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( !(assertion) ) \
|
||||
{ \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_require(assertion, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_check(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( !(assertion) ) \
|
||||
{ \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#define XThrow(error, operation) XThrowIf(true, error, operation)
|
||||
#define XThrowIfErr(error) XThrowIfError(error, #error)
|
||||
|
||||
#endif // __CAXException_h__
|
||||
|
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
File: ComponentBase.cpp
|
||||
Abstract: ComponentBase.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "ComponentBase.h"
|
||||
#include "CAXException.h"
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_mutex_t ComponentInitLocker::sComponentOpenMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_once_t ComponentInitLocker::sOnce = PTHREAD_ONCE_INIT;
|
||||
|
||||
void ComponentInitLocker::InitComponentInitLocker()
|
||||
{
|
||||
// have to do this because OS X lacks PTHREAD_MUTEX_RECURSIVE_INITIALIZER_NP
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&sComponentOpenMutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
#elif TARGET_OS_WIN32
|
||||
CAGuard ComponentInitLocker::sComponentOpenGuard("sComponentOpenGuard");
|
||||
#endif
|
||||
|
||||
ComponentBase::EInstanceType ComponentBase::sNewInstanceType;
|
||||
|
||||
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc);
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY && !TARGET_OS_WIN32
|
||||
static OSStatus CMgr_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc);
|
||||
#endif
|
||||
|
||||
ComponentBase::ComponentBase(AudioComponentInstance inInstance)
|
||||
: mComponentInstance(inInstance),
|
||||
mInstanceType(sNewInstanceType)
|
||||
{
|
||||
GetComponentDescription();
|
||||
}
|
||||
|
||||
ComponentBase::~ComponentBase()
|
||||
{
|
||||
}
|
||||
|
||||
void ComponentBase::PostConstructor()
|
||||
{
|
||||
}
|
||||
|
||||
void ComponentBase::PreDestructor()
|
||||
{
|
||||
}
|
||||
|
||||
#define ACPI ((AudioComponentPlugInInstance *)self)
|
||||
#define ACImp ((ComponentBase *)&ACPI->mInstanceStorage)
|
||||
|
||||
OSStatus ComponentBase::AP_Open(void *self, AudioUnit compInstance)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
ComponentInitLocker lock;
|
||||
|
||||
ComponentBase::sNewInstanceType = ComponentBase::kAudioComponentInstance;
|
||||
ComponentBase *cb = (ComponentBase *)(*ACPI->mConstruct)(&ACPI->mInstanceStorage, compInstance);
|
||||
cb->PostConstructor(); // allows base class to do additional initialization
|
||||
// once the derived class is fully constructed
|
||||
result = noErr;
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
if (result)
|
||||
delete ACPI;
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus ComponentBase::AP_Close(void *self)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
if (ACImp) {
|
||||
ACImp->PreDestructor();
|
||||
(*ACPI->mDestruct)(&ACPI->mInstanceStorage);
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
OSStatus ComponentBase::Version()
|
||||
{
|
||||
return 0x00000001;
|
||||
}
|
||||
|
||||
OSStatus ComponentBase::ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This)
|
||||
{
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
|
||||
OSStatus result = noErr;
|
||||
|
||||
switch (p->what) {
|
||||
case kComponentCloseSelect:
|
||||
This->PreDestructor();
|
||||
delete This;
|
||||
break;
|
||||
|
||||
case kComponentVersionSelect:
|
||||
result = This->Version();
|
||||
break;
|
||||
|
||||
case kComponentCanDoSelect:
|
||||
switch (GetSelectorForCanDo(p)) {
|
||||
case kComponentOpenSelect:
|
||||
case kComponentCloseSelect:
|
||||
case kComponentVersionSelect:
|
||||
case kComponentCanDoSelect:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
result = badComponentSelector;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 ComponentBase::GetSelectorForCanDo(ComponentParameters *params)
|
||||
{
|
||||
if (params->what != kComponentCanDoSelect) return 0;
|
||||
|
||||
#if TARGET_CPU_X86
|
||||
SInt16 sel = params->params[0];
|
||||
#elif TARGET_CPU_X86_64
|
||||
SInt16 sel = params->params[1];
|
||||
#elif TARGET_CPU_PPC
|
||||
SInt16 sel = (params->params[0] >> 16);
|
||||
#else
|
||||
SInt16 sel = params->params[0];
|
||||
#endif
|
||||
|
||||
return sel;
|
||||
/*
|
||||
printf ("flags:%d, paramSize: %d, what: %d\n\t", params->flags, params->paramSize, params->what);
|
||||
for (int i = 0; i < params->paramSize; ++i) {
|
||||
printf ("[%d]:%d(0x%x), ", i, params->params[i], params->params[i]);
|
||||
}
|
||||
printf("\n\tsel:%d\n", sel);
|
||||
*/
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if CA_DO_NOT_USE_AUDIO_COMPONENT
|
||||
static OSStatus ComponentBase_GetComponentDescription (const AudioComponentInstance & inInstance, AudioComponentDescription &outDesc);
|
||||
#endif
|
||||
|
||||
AudioComponentDescription ComponentBase::GetComponentDescription() const
|
||||
{
|
||||
AudioComponentDescription desc;
|
||||
OSStatus result = 1;
|
||||
|
||||
if (IsPluginObject()) {
|
||||
ca_require_noerr(result = CB_GetComponentDescription (mComponentInstance, &desc), home);
|
||||
}
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
else {
|
||||
ca_require_noerr(result = CMgr_GetComponentDescription (mComponentInstance, &desc), home);
|
||||
}
|
||||
#endif
|
||||
|
||||
home:
|
||||
if (result)
|
||||
memset (&desc, 0, sizeof(AudioComponentDescription));
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
#if CA_USE_AUDIO_PLUGIN_ONLY
|
||||
// everything we need is there and we should be linking against it
|
||||
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
|
||||
{
|
||||
AudioComponent comp = AudioComponentInstanceGetComponent(inInstance);
|
||||
if (comp)
|
||||
return AudioComponentGetDescription(comp, outDesc);
|
||||
|
||||
return kAudio_ParamError;
|
||||
}
|
||||
|
||||
#elif !TARGET_OS_WIN32
|
||||
// these are the direct dependencies on ComponentMgr calls that an AU
|
||||
// that is a component mgr is dependent on
|
||||
|
||||
// these are dynamically loaded so that these calls will work on Leopard
|
||||
#include <dlfcn.h>
|
||||
|
||||
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
|
||||
{
|
||||
typedef AudioComponent (*AudioComponentInstanceGetComponentProc) (AudioComponentInstance);
|
||||
static AudioComponentInstanceGetComponentProc aciGCProc = NULL;
|
||||
|
||||
typedef OSStatus (*AudioComponentGetDescriptionProc)(AudioComponent, AudioComponentDescription *);
|
||||
static AudioComponentGetDescriptionProc acGDProc = NULL;
|
||||
|
||||
static int doneInit = 0;
|
||||
if (doneInit == 0) {
|
||||
doneInit = 1;
|
||||
void* theImage = dlopen("/System/Library/Frameworks/AudioUnit.framework/AudioUnit", RTLD_LAZY);
|
||||
if (theImage != NULL)
|
||||
{
|
||||
aciGCProc = (AudioComponentInstanceGetComponentProc)dlsym (theImage, "AudioComponentInstanceGetComponent");
|
||||
if (aciGCProc) {
|
||||
acGDProc = (AudioComponentGetDescriptionProc)dlsym (theImage, "AudioComponentGetDescription");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus result = kAudio_UnimplementedError;
|
||||
if (acGDProc && aciGCProc) {
|
||||
AudioComponent comp = (*aciGCProc)(inInstance);
|
||||
if (comp)
|
||||
result = (*acGDProc)(comp, outDesc);
|
||||
}
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
else {
|
||||
result = CMgr_GetComponentDescription (inInstance, outDesc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
// these are the direct dependencies on ComponentMgr calls that an AU
|
||||
// that is a component mgr is dependent on
|
||||
|
||||
// these are dynamically loaded
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include "CAXException.h"
|
||||
#include "ComponentBase.h"
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Component Manager
|
||||
// Used for fast dispatch with audio units
|
||||
typedef Handle (*GetComponentInstanceStorageProc)(ComponentInstance aComponentInstance);
|
||||
static GetComponentInstanceStorageProc sGetComponentInstanceStorageProc = NULL;
|
||||
|
||||
typedef OSErr (*GetComponentInfoProc)(Component, ComponentDescription *, void*, void*, void*);
|
||||
static GetComponentInfoProc sGetComponentInfoProc = NULL;
|
||||
|
||||
typedef void (*SetComponentInstanceStorageProc)(ComponentInstance, Handle);
|
||||
static SetComponentInstanceStorageProc sSetComponentInstanceStorageProc = NULL;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
static void CSInitOnce(void* /*unused*/)
|
||||
{
|
||||
void *theImage = dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_LAZY);
|
||||
if (!theImage) return;
|
||||
|
||||
sGetComponentInstanceStorageProc = (GetComponentInstanceStorageProc) dlsym(theImage, "GetComponentInstanceStorage");
|
||||
sGetComponentInfoProc = (GetComponentInfoProc)dlsym (theImage, "GetComponentInfo");
|
||||
sSetComponentInstanceStorageProc = (SetComponentInstanceStorageProc) dlsym(theImage, "SetComponentInstanceStorage");
|
||||
}
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
static dispatch_once_t sCSInitOnce = 0;
|
||||
|
||||
static void CSInit ()
|
||||
{
|
||||
dispatch_once_f(&sCSInitOnce, NULL, CSInitOnce);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void CSInit ()
|
||||
{
|
||||
static int sDoCSLoad = 1;
|
||||
if (sDoCSLoad) {
|
||||
sDoCSLoad = 0;
|
||||
CSInitOnce(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
OSStatus CMgr_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
|
||||
{
|
||||
CSInit();
|
||||
if (sGetComponentInfoProc)
|
||||
return (*sGetComponentInfoProc)((Component)inInstance, (ComponentDescription*)outDesc, NULL, NULL, NULL);
|
||||
return kAudio_UnimplementedError;
|
||||
}
|
||||
|
||||
Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance)
|
||||
{
|
||||
CSInit();
|
||||
if (sGetComponentInstanceStorageProc)
|
||||
return (*sGetComponentInstanceStorageProc)(aComponentInstance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage)
|
||||
{
|
||||
CSInit();
|
||||
if (sSetComponentInstanceStorageProc)
|
||||
(*sSetComponentInstanceStorageProc)(aComponentInstance, theStorage);
|
||||
}
|
||||
#endif // !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
|
||||
#else
|
||||
//#include "ComponentManagerDependenciesWin.h"
|
||||
// everything we need is there and we should be linking against it
|
||||
static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc)
|
||||
{
|
||||
AudioComponent comp = AudioComponentInstanceGetComponent(inInstance);
|
||||
if (comp)
|
||||
return AudioComponentGetDescription(comp, outDesc);
|
||||
|
||||
return kAudio_ParamError;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,353 +0,0 @@
|
|||
/*
|
||||
File: ComponentBase.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __ComponentBase_h__
|
||||
#define __ComponentBase_h__
|
||||
|
||||
#include <new>
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAXException.h"
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h>
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
|
||||
#define AudioComponentInstance ComponentInstance
|
||||
#define AudioComponentDescription ComponentDescription
|
||||
#define AudioComponent Component
|
||||
#endif
|
||||
Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance);
|
||||
void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage);
|
||||
#endif
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
||||
typedef Float32 AudioUnitParameterValue;
|
||||
#endif
|
||||
#if COREAUDIOTYPES_VERSION < 1051
|
||||
typedef Float32 AudioUnitSampleType;
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_WIN32
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#include "CAGuard.h"
|
||||
#endif
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
#include "ComponentManagerDependenciesWin.h"
|
||||
#endif
|
||||
#include "AudioUnit.h"
|
||||
#include "CAGuard.h"
|
||||
#endif
|
||||
|
||||
#ifndef COMPONENT_THROW
|
||||
#if VERBOSE_COMPONENT_THROW
|
||||
#define COMPONENT_THROW(throw_err) \
|
||||
do { DebugMessage(#throw_err); throw static_cast<OSStatus>(throw_err); } while (0)
|
||||
#else
|
||||
#define COMPONENT_THROW(throw_err) \
|
||||
throw static_cast<OSStatus>(throw_err)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define COMPONENT_CATCH \
|
||||
catch (const CAXException &ex) { result = ex.mError; } \
|
||||
catch (std::bad_alloc &) { result = kAudio_MemFullError; } \
|
||||
catch (OSStatus catch_err) { result = catch_err; } \
|
||||
catch (OSErr catch_err) { result = catch_err; } \
|
||||
catch (...) { result = -1; }
|
||||
|
||||
/*! @class ComponentBase */
|
||||
class ComponentBase {
|
||||
public:
|
||||
// classic MacErrors
|
||||
enum { noErr = 0};
|
||||
|
||||
/*! @ctor ComponentBase */
|
||||
ComponentBase(AudioComponentInstance inInstance);
|
||||
|
||||
/*! @dtor ~ComponentBase */
|
||||
virtual ~ComponentBase();
|
||||
|
||||
/*! @method PostConstructor */
|
||||
virtual void PostConstructor();
|
||||
|
||||
/*! @method PreDestructor */
|
||||
virtual void PreDestructor();
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
/*! @method Version */
|
||||
virtual OSStatus Version();
|
||||
|
||||
/*! @method ComponentEntryDispatch */
|
||||
static OSStatus ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This);
|
||||
|
||||
/*! GetSelectorForCanDo */
|
||||
static SInt16 GetSelectorForCanDo(ComponentParameters *params);
|
||||
#endif
|
||||
|
||||
/*! @method GetComponentInstance */
|
||||
AudioComponentInstance GetComponentInstance() const { return mComponentInstance; }
|
||||
|
||||
/*! @method GetComponentDescription */
|
||||
AudioComponentDescription GetComponentDescription() const;
|
||||
|
||||
// This global variable is so that new instances know how they were instantiated: via the Component Manager,
|
||||
// or as AudioComponents. It's ugly, but preferable to altering the constructor of every class in the hierarchy.
|
||||
// It's safe because construction is protected by ComponentInitLocker.
|
||||
enum EInstanceType { kComponentMgrInstance, kAudioComponentInstance };
|
||||
static EInstanceType sNewInstanceType;
|
||||
|
||||
/*! @method IsPluginObject */
|
||||
bool IsPluginObject () const { return mInstanceType == kAudioComponentInstance; }
|
||||
/*! @method IsCMgrObject */
|
||||
bool IsCMgrObject () const { return mInstanceType == kComponentMgrInstance; }
|
||||
|
||||
/*! @method AP_Open */
|
||||
static OSStatus AP_Open(void *self, AudioUnit compInstance);
|
||||
|
||||
/*! @method AP_Close */
|
||||
static OSStatus AP_Close(void *self);
|
||||
|
||||
protected:
|
||||
/*! @var mComponentInstance */
|
||||
AudioComponentInstance mComponentInstance;
|
||||
EInstanceType mInstanceType;
|
||||
};
|
||||
|
||||
class ComponentInitLocker
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
public:
|
||||
ComponentInitLocker()
|
||||
{
|
||||
pthread_once(&sOnce, InitComponentInitLocker);
|
||||
pthread_mutex_lock(&sComponentOpenMutex);
|
||||
mPreviousNewInstanceType = ComponentBase::sNewInstanceType;
|
||||
}
|
||||
~ComponentInitLocker()
|
||||
{
|
||||
ComponentBase::sNewInstanceType = mPreviousNewInstanceType;
|
||||
pthread_mutex_unlock(&sComponentOpenMutex);
|
||||
}
|
||||
|
||||
// There are situations (11844772) where we need to be able to release the lock early.
|
||||
class Unlocker {
|
||||
public:
|
||||
Unlocker()
|
||||
{
|
||||
pthread_mutex_unlock(&sComponentOpenMutex);
|
||||
}
|
||||
~Unlocker()
|
||||
{
|
||||
pthread_mutex_lock(&sComponentOpenMutex);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static pthread_mutex_t sComponentOpenMutex;
|
||||
static pthread_once_t sOnce;
|
||||
static void InitComponentInitLocker();
|
||||
|
||||
#elif TARGET_OS_WIN32
|
||||
public:
|
||||
bool sNeedsUnlocking;
|
||||
ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); }
|
||||
~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } }
|
||||
private:
|
||||
static CAGuard sComponentOpenGuard;
|
||||
#endif
|
||||
|
||||
private:
|
||||
ComponentBase::EInstanceType mPreviousNewInstanceType;
|
||||
};
|
||||
|
||||
/*! @class AudioComponentPlugInInstance */
|
||||
struct AudioComponentPlugInInstance {
|
||||
AudioComponentPlugInInterface mPlugInInterface;
|
||||
void * (*mConstruct)(void *memory, AudioComponentInstance ci);
|
||||
void (*mDestruct)(void *memory);
|
||||
void * mPad[2]; // pad to a 16-byte boundary (in either 32 or 64 bit mode)
|
||||
UInt32 mInstanceStorage; // the ACI implementation object is constructed into this memory
|
||||
// this member is just a placeholder. it is aligned to a 16byte boundary
|
||||
};
|
||||
|
||||
/*! @class APFactory */
|
||||
template <class APMethodLookup, class Implementor>
|
||||
class APFactory {
|
||||
public:
|
||||
static void *Construct(void *memory, AudioComponentInstance compInstance)
|
||||
{
|
||||
return new(memory) Implementor(compInstance);
|
||||
}
|
||||
|
||||
static void Destruct(void *memory)
|
||||
{
|
||||
((Implementor *)memory)->~Implementor();
|
||||
}
|
||||
|
||||
// This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance.
|
||||
// The actual implementation object is not created until Open().
|
||||
static AudioComponentPlugInInterface *Factory(const AudioComponentDescription * /* inDesc */)
|
||||
{
|
||||
AudioComponentPlugInInstance *acpi =
|
||||
(AudioComponentPlugInInstance *)malloc( offsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor) );
|
||||
acpi->mPlugInInterface.Open = ComponentBase::AP_Open;
|
||||
acpi->mPlugInInterface.Close = ComponentBase::AP_Close;
|
||||
acpi->mPlugInInterface.Lookup = APMethodLookup::Lookup;
|
||||
acpi->mPlugInInterface.reserved = NULL;
|
||||
acpi->mConstruct = Construct;
|
||||
acpi->mDestruct = Destruct;
|
||||
acpi->mPad[0] = NULL;
|
||||
acpi->mPad[1] = NULL;
|
||||
return (AudioComponentPlugInInterface*)acpi;
|
||||
}
|
||||
|
||||
// This is for runtime registration (not for plug-ins loaded from bundles).
|
||||
static AudioComponent Register(UInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags=0)
|
||||
{
|
||||
AudioComponentDescription desc = { type, subtype, manuf, flags, 0 };
|
||||
return AudioComponentRegister(&desc, name, vers, Factory);
|
||||
}
|
||||
};
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
/*! @class ComponentEntryPoint
|
||||
* @discussion This is only used for a component manager version
|
||||
*/
|
||||
template <class Class>
|
||||
class ComponentEntryPoint {
|
||||
public:
|
||||
/*! @method Dispatch */
|
||||
static OSStatus Dispatch(ComponentParameters *params, Class *obj)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
try {
|
||||
if (params->what == kComponentOpenSelect) {
|
||||
// solve a host of initialization thread safety issues.
|
||||
ComponentInitLocker lock;
|
||||
|
||||
ComponentBase::sNewInstanceType = ComponentBase::kComponentMgrInstance;
|
||||
ComponentInstance ci = (ComponentInstance)(params->params[0]);
|
||||
Class *This = new Class((AudioComponentInstance)ci);
|
||||
This->PostConstructor(); // allows base class to do additional initialization
|
||||
// once the derived class is fully constructed
|
||||
|
||||
CMgr_SetComponentInstanceStorage(ci, (Handle)This);
|
||||
} else
|
||||
result = Class::ComponentEntryDispatch(params, obj);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*! @method Register */
|
||||
static Component Register(OSType compType, OSType subType, OSType manufacturer)
|
||||
{
|
||||
ComponentDescription description = {compType, subType, manufacturer, 0, 0};
|
||||
Component component = RegisterComponent(&description, (ComponentRoutineUPP) Dispatch, registerComponentGlobal, NULL, NULL, NULL);
|
||||
if (component != NULL) {
|
||||
SetDefaultComponent(component, defaultComponentAnyFlagsAnyManufacturerAnySubType);
|
||||
}
|
||||
return component;
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: Component Mgr is deprecated in ML.
|
||||
// this macro should not be used with new audio components
|
||||
// it is only for backwards compatibility with Lion and SL.
|
||||
// this macro registers both a plugin and a component mgr version.
|
||||
#define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \
|
||||
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \
|
||||
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \
|
||||
return ComponentEntryPoint<Class>::Dispatch(params, obj); \
|
||||
} \
|
||||
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \
|
||||
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \
|
||||
return FactoryType<Class>::Factory(inDesc); \
|
||||
}
|
||||
// the only component we still support are the carbon based view components
|
||||
// you should be using this macro now to exclusively register those types
|
||||
#define VIEW_COMPONENT_ENTRY(Class) \
|
||||
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \
|
||||
extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \
|
||||
return ComponentEntryPoint<Class>::Dispatch(params, obj); \
|
||||
}
|
||||
|
||||
/*! @class ComponentRegistrar */
|
||||
template <class Class, OSType Type, OSType Subtype, OSType Manufacturer>
|
||||
class ComponentRegistrar {
|
||||
public:
|
||||
/*! @ctor ComponentRegistrar */
|
||||
ComponentRegistrar() { ComponentEntryPoint<Class>::Register(Type, Subtype, Manufacturer); }
|
||||
};
|
||||
|
||||
#define COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \
|
||||
static ComponentRegistrar<Class, Type, Subtype, Manufacturer> gRegistrar##Class
|
||||
#else
|
||||
#define COMPONENT_ENTRY(Class)
|
||||
#define COMPONENT_REGISTER(Class)
|
||||
// this macro is used to generate the Entry Point for a given Audio Plugin
|
||||
// you should be using this macro now with audio components
|
||||
#define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \
|
||||
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \
|
||||
extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \
|
||||
return FactoryType<Class>::Factory(inDesc); \
|
||||
}
|
||||
|
||||
#endif // !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
|
||||
|
||||
#endif // __ComponentBase_h__
|
||||
|
|
@ -1,354 +0,0 @@
|
|||
/*
|
||||
File: MusicDeviceBase.cpp
|
||||
Abstract: MusicDeviceBase.h
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "MusicDeviceBase.h"
|
||||
|
||||
// compatibility with older OS SDK releases
|
||||
typedef OSStatus
|
||||
(*TEMP_MusicDeviceMIDIEventProc)( void * inComponentStorage,
|
||||
UInt32 inStatus,
|
||||
UInt32 inData1,
|
||||
UInt32 inData2,
|
||||
UInt32 inOffsetSampleFrame);
|
||||
|
||||
typedef OSStatus
|
||||
(*TEMP_MusicDeviceStartNoteProc)( void * inComponentStorage,
|
||||
MusicDeviceInstrumentID inInstrument,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID * outNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame,
|
||||
const MusicDeviceNoteParams * inParams);
|
||||
|
||||
typedef OSStatus
|
||||
(*TEMP_MusicDeviceStopNoteProc)(void * inComponentStorage,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID inNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame);
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
|
||||
static OSStatus MusicDeviceBaseMIDIEvent(void * inComponentStorage,
|
||||
UInt32 inStatus,
|
||||
UInt32 inData1,
|
||||
UInt32 inData2,
|
||||
UInt32 inOffsetSampleFrame);
|
||||
|
||||
static OSStatus MusicDeviceBaseStartNote( void * inComponentStorage,
|
||||
MusicDeviceInstrumentID inInstrument,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID * outNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame,
|
||||
const MusicDeviceNoteParams * inParams);
|
||||
|
||||
static OSStatus MusicDeviceBaseStopNote(void * inComponentStorage,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID inNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame);
|
||||
|
||||
#endif
|
||||
|
||||
MusicDeviceBase::MusicDeviceBase(AudioComponentInstance inInstance,
|
||||
UInt32 numInputs,
|
||||
UInt32 numOutputs,
|
||||
UInt32 numGroups)
|
||||
: AUBase(inInstance, numInputs, numOutputs, numGroups),
|
||||
AUMIDIBase(this)
|
||||
{
|
||||
}
|
||||
|
||||
OSStatus MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 & outDataSize,
|
||||
Boolean & outWritable)
|
||||
{
|
||||
OSStatus result;
|
||||
|
||||
switch (inID)
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
case kMusicDeviceProperty_InstrumentCount:
|
||||
if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
|
||||
outDataSize = sizeof(UInt32);
|
||||
outWritable = false;
|
||||
result = noErr;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
result = AUBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
|
||||
|
||||
if (result == kAudioUnitErr_InvalidProperty)
|
||||
result = AUMIDIBase::DelegateGetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus MusicDeviceBase::GetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
void * outData)
|
||||
{
|
||||
OSStatus result;
|
||||
|
||||
switch (inID)
|
||||
{
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
case kAudioUnitProperty_FastDispatch:
|
||||
if (!IsCMgrObject()) return kAudioUnitErr_InvalidProperty;
|
||||
if (inElement == kMusicDeviceMIDIEventSelect) {
|
||||
*(TEMP_MusicDeviceMIDIEventProc *)outData = MusicDeviceBaseMIDIEvent;
|
||||
return noErr;
|
||||
}
|
||||
else if (inElement == kMusicDeviceStartNoteSelect) {
|
||||
*(TEMP_MusicDeviceStartNoteProc *)outData = MusicDeviceBaseStartNote;
|
||||
return noErr;
|
||||
}
|
||||
else if (inElement == kMusicDeviceStopNoteSelect) {
|
||||
*(TEMP_MusicDeviceStopNoteProc *)outData = MusicDeviceBaseStopNote;
|
||||
return noErr;
|
||||
}
|
||||
return kAudioUnitErr_InvalidElement;
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
case kMusicDeviceProperty_InstrumentCount:
|
||||
if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
|
||||
return GetInstrumentCount (*(UInt32*)outData);
|
||||
#endif
|
||||
default:
|
||||
result = AUBase::GetProperty (inID, inScope, inElement, outData);
|
||||
|
||||
if (result == kAudioUnitErr_InvalidProperty)
|
||||
result = AUMIDIBase::DelegateGetProperty (inID, inScope, inElement, outData);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
OSStatus MusicDeviceBase::SetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
const void * inData,
|
||||
UInt32 inDataSize)
|
||||
|
||||
{
|
||||
|
||||
OSStatus result = AUBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
|
||||
|
||||
if (result == kAudioUnitErr_InvalidProperty)
|
||||
result = AUMIDIBase::DelegateSetProperty (inID, inScope, inElement, inData, inDataSize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// For a MusicDevice that doesn't support separate instruments (ie. is mono-timbral)
|
||||
// then this call should return an instrument count of zero and noErr
|
||||
OSStatus MusicDeviceBase::GetInstrumentCount (UInt32 &outInstCount) const
|
||||
{
|
||||
outInstCount = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus MusicDeviceBase::HandleNoteOn( UInt8 inChannel,
|
||||
UInt8 inNoteNumber,
|
||||
UInt8 inVelocity,
|
||||
UInt32 inStartFrame)
|
||||
{
|
||||
MusicDeviceNoteParams params;
|
||||
params.argCount = 2;
|
||||
params.mPitch = inNoteNumber;
|
||||
params.mVelocity = inVelocity;
|
||||
return StartNote (kMusicNoteEvent_UseGroupInstrument, inChannel, NULL, inStartFrame, params);
|
||||
}
|
||||
|
||||
OSStatus MusicDeviceBase::HandleNoteOff( UInt8 inChannel,
|
||||
UInt8 inNoteNumber,
|
||||
UInt8 inVelocity,
|
||||
UInt32 inStartFrame)
|
||||
{
|
||||
return StopNote (inChannel, inNoteNumber, inStartFrame);
|
||||
}
|
||||
|
||||
OSStatus
|
||||
MusicDeviceBase::HandleStartNoteMessage (MusicDeviceInstrumentID inInstrument,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID * outNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame,
|
||||
const MusicDeviceNoteParams * inParams)
|
||||
{
|
||||
if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError;
|
||||
|
||||
if (!IsInitialized()) return kAudioUnitErr_Uninitialized;
|
||||
|
||||
return StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
|
||||
}
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#if __LP64__
|
||||
// comp instance, parameters in forward order
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_index + 1];
|
||||
#else
|
||||
// parameters in reverse order, then comp instance
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index];
|
||||
#endif
|
||||
#elif TARGET_OS_WIN32
|
||||
// (no comp instance), parameters in forward order
|
||||
#define PARAM(_typ, _name, _index, _nparams) \
|
||||
_typ _name = *(_typ *)¶ms->params[_index];
|
||||
#endif
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
OSStatus MusicDeviceBase::ComponentEntryDispatch( ComponentParameters * params,
|
||||
MusicDeviceBase * This)
|
||||
{
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
|
||||
OSStatus result;
|
||||
|
||||
switch (params->what) {
|
||||
case kMusicDeviceMIDIEventSelect:
|
||||
case kMusicDeviceSysExSelect:
|
||||
{
|
||||
result = AUMIDIBase::ComponentEntryDispatch (params, This);
|
||||
}
|
||||
break;
|
||||
case kMusicDevicePrepareInstrumentSelect:
|
||||
{
|
||||
PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1);
|
||||
result = This->PrepareInstrument(inInstrument);
|
||||
}
|
||||
break;
|
||||
case kMusicDeviceReleaseInstrumentSelect:
|
||||
{
|
||||
PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1);
|
||||
result = This->ReleaseInstrument(inInstrument);
|
||||
}
|
||||
break;
|
||||
case kMusicDeviceStartNoteSelect:
|
||||
{
|
||||
PARAM(MusicDeviceInstrumentID, pbinInstrument, 0, 5);
|
||||
PARAM(MusicDeviceGroupID, pbinGroupID, 1, 5);
|
||||
PARAM(NoteInstanceID *, pboutNoteInstanceID, 2, 5);
|
||||
PARAM(UInt32, pbinOffsetSampleFrame, 3, 5);
|
||||
PARAM(const MusicDeviceNoteParams *, pbinParams, 4, 5);
|
||||
result = This->HandleStartNoteMessage(pbinInstrument, pbinGroupID, pboutNoteInstanceID, pbinOffsetSampleFrame, pbinParams);
|
||||
}
|
||||
break;
|
||||
case kMusicDeviceStopNoteSelect:
|
||||
{
|
||||
PARAM(MusicDeviceGroupID, pbinGroupID, 0, 3);
|
||||
PARAM(NoteInstanceID, pbinNoteInstanceID, 1, 3);
|
||||
PARAM(UInt32, pbinOffsetSampleFrame, 2, 3);
|
||||
result = This->StopNote(pbinGroupID, pbinNoteInstanceID, pbinOffsetSampleFrame);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
result = AUBase::ComponentEntryDispatch(params, This);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
|
||||
// fast dispatch
|
||||
static OSStatus MusicDeviceBaseMIDIEvent(void * inComponentStorage,
|
||||
UInt32 inStatus,
|
||||
UInt32 inData1,
|
||||
UInt32 inData2,
|
||||
UInt32 inOffsetSampleFrame)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
result = This->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus MusicDeviceBaseStartNote( void * inComponentStorage,
|
||||
MusicDeviceInstrumentID inInstrument,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID * outNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame,
|
||||
const MusicDeviceNoteParams * inParams)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError;
|
||||
MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
result = This->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
OSStatus MusicDeviceBaseStopNote(void * inComponentStorage,
|
||||
MusicDeviceGroupID inGroupID,
|
||||
NoteInstanceID inNoteInstanceID,
|
||||
UInt32 inOffsetSampleFrame)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
try {
|
||||
MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
|
||||
if (This == NULL) return kAudio_ParamError;
|
||||
result = This->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);
|
||||
}
|
||||
COMPONENT_CATCH
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
File: MusicDeviceBase.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __MusicDeviceBase_h__
|
||||
#define __MusicDeviceBase_h__
|
||||
|
||||
#include "AUMIDIBase.h"
|
||||
|
||||
// ________________________________________________________________________
|
||||
// MusicDeviceBase
|
||||
//
|
||||
|
||||
/*! @class MusicDeviceBase */
|
||||
class MusicDeviceBase : public AUBase, public AUMIDIBase {
|
||||
public:
|
||||
/*! @ctor MusicDeviceBase */
|
||||
MusicDeviceBase( AudioComponentInstance inInstance,
|
||||
UInt32 numInputs,
|
||||
UInt32 numOutputs,
|
||||
UInt32 numGroups = 0);
|
||||
|
||||
|
||||
virtual OSStatus MIDIEvent( UInt32 inStatus,
|
||||
UInt32 inData1,
|
||||
UInt32 inData2,
|
||||
UInt32 inOffsetSampleFrame)
|
||||
{
|
||||
return AUMIDIBase::MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame);
|
||||
}
|
||||
|
||||
/*! @method SysEx */
|
||||
virtual OSStatus SysEx( const UInt8 * inData,
|
||||
UInt32 inLength)
|
||||
{
|
||||
return AUMIDIBase::SysEx (inData, inLength);
|
||||
}
|
||||
|
||||
/*! @method GetPropertyInfo */
|
||||
virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
UInt32 & outDataSize,
|
||||
Boolean & outWritable);
|
||||
|
||||
/*! @method GetProperty */
|
||||
virtual OSStatus GetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
void * outData);
|
||||
|
||||
/*! @method SetProperty */
|
||||
virtual OSStatus SetProperty( AudioUnitPropertyID inID,
|
||||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
const void * inData,
|
||||
UInt32 inDataSize);
|
||||
|
||||
/*! @method HandleNoteOn */
|
||||
virtual OSStatus HandleNoteOn( UInt8 inChannel,
|
||||
UInt8 inNoteNumber,
|
||||
UInt8 inVelocity,
|
||||
UInt32 inStartFrame);
|
||||
|
||||
/*! @method HandleNoteOff */
|
||||
virtual OSStatus HandleNoteOff( UInt8 inChannel,
|
||||
UInt8 inNoteNumber,
|
||||
UInt8 inVelocity,
|
||||
UInt32 inStartFrame);
|
||||
|
||||
/*! @method GetInstrumentCount */
|
||||
virtual OSStatus GetInstrumentCount ( UInt32 &outInstCount) const;
|
||||
|
||||
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
||||
// component dispatcher
|
||||
/*! @method ComponentEntryDispatch */
|
||||
static OSStatus ComponentEntryDispatch( ComponentParameters * params,
|
||||
MusicDeviceBase * This);
|
||||
#endif
|
||||
private:
|
||||
OSStatus HandleStartNoteMessage (MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams);
|
||||
};
|
||||
|
||||
#endif // __MusicDeviceBase_h__
|
||||
|
|
@ -52,7 +52,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wshorten-64-to-32",
|
|||
#include <AudioToolbox/AudioUnitUtilities.h>
|
||||
#include <CoreMIDI/MIDIServices.h>
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#include "CoreAudioUtilityClasses/MusicDeviceBase.h"
|
||||
#include "AudioUnitSDK/MusicDeviceBase.h"
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
|
|
@ -73,6 +73,8 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
|
||||
//==============================================================================
|
||||
using namespace juce;
|
||||
|
||||
|
|
@ -101,7 +103,7 @@ struct AudioProcessorHolder
|
|||
|
||||
//==============================================================================
|
||||
class JuceAU : public AudioProcessorHolder,
|
||||
public MusicDeviceBase,
|
||||
public ausdk::MusicDeviceBase,
|
||||
public AudioProcessorListener,
|
||||
public AudioProcessorParameter::Listener
|
||||
{
|
||||
|
|
@ -239,24 +241,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static OSStatus ComponentEntryDispatch (ComponentParameters* params, JuceAU* effect)
|
||||
{
|
||||
if (effect == nullptr)
|
||||
return paramErr;
|
||||
|
||||
switch (params->what)
|
||||
{
|
||||
case kMusicDeviceMIDIEventSelect:
|
||||
case kMusicDeviceSysExSelect:
|
||||
return AUMIDIBase::ComponentEntryDispatch (params, effect);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return MusicDeviceBase::ComponentEntryDispatch (params, effect);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool BusCountWritable (AudioUnitScope scope) override
|
||||
{
|
||||
|
|
@ -380,7 +364,7 @@ public:
|
|||
AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
UInt32& outDataSize,
|
||||
Boolean& outWritable) override
|
||||
bool& outWritable) override
|
||||
{
|
||||
if (inScope == kAudioUnitScope_Global)
|
||||
{
|
||||
|
|
@ -813,8 +797,10 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
UInt32 GetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element,
|
||||
AudioChannelLayout* outLayoutPtr, Boolean& outWritable) override
|
||||
UInt32 GetAudioChannelLayout (AudioUnitScope scope,
|
||||
AudioUnitElement element,
|
||||
AudioChannelLayout* outLayoutPtr,
|
||||
bool& outWritable) override
|
||||
{
|
||||
outWritable = false;
|
||||
|
||||
|
|
@ -839,22 +825,17 @@ public:
|
|||
return sizeInBytes;
|
||||
}
|
||||
|
||||
UInt32 GetChannelLayoutTags (AudioUnitScope scope, AudioUnitElement element, AudioChannelLayoutTag* outLayoutTags) override
|
||||
std::vector<AudioChannelLayoutTag> GetChannelLayoutTags (AudioUnitScope inScope, AudioUnitElement inElement) override
|
||||
{
|
||||
const auto info = getElementInfo (scope, element);
|
||||
const auto info = getElementInfo (inScope, inElement);
|
||||
|
||||
if (info.error != noErr)
|
||||
return 0;
|
||||
return {};
|
||||
|
||||
if (busIgnoresLayout (info.isInput, info.busNr))
|
||||
return 0;
|
||||
return {};
|
||||
|
||||
const Array<AudioChannelLayoutTag>& layouts = getSupportedBusLayouts (info.isInput, info.busNr);
|
||||
|
||||
if (outLayoutTags != nullptr)
|
||||
std::copy (layouts.begin(), layouts.end(), outLayoutTags);
|
||||
|
||||
return (UInt32) layouts.size();
|
||||
return getSupportedBusLayouts (info.isInput, info.busNr);
|
||||
}
|
||||
|
||||
OSStatus SetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout) override
|
||||
|
|
@ -870,34 +851,29 @@ public:
|
|||
if (inLayout == nullptr)
|
||||
return kAudioUnitErr_InvalidPropertyValue;
|
||||
|
||||
if (const AUIOElement* ioElement = GetIOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element))
|
||||
{
|
||||
const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout);
|
||||
const int currentNumChannels = static_cast<int> (ioElement->GetStreamFormat().NumberChannels());
|
||||
const int newChannelNum = newChannelSet.size();
|
||||
auto& ioElement = IOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element);
|
||||
|
||||
if (currentNumChannels != newChannelNum)
|
||||
return kAudioUnitErr_InvalidPropertyValue;
|
||||
const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout);
|
||||
const int currentNumChannels = static_cast<int> (ioElement.NumberChannels());
|
||||
const int newChannelNum = newChannelSet.size();
|
||||
|
||||
// check if the new layout could be potentially set
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
|
||||
if (currentNumChannels != newChannelNum)
|
||||
return kAudioUnitErr_InvalidPropertyValue;
|
||||
|
||||
if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs))
|
||||
return kAudioUnitErr_FormatNotSupported;
|
||||
#else
|
||||
if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet))
|
||||
return kAudioUnitErr_FormatNotSupported;
|
||||
#endif
|
||||
// check if the new layout could be potentially set
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
|
||||
|
||||
getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet);
|
||||
if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs))
|
||||
return kAudioUnitErr_FormatNotSupported;
|
||||
#else
|
||||
if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet))
|
||||
return kAudioUnitErr_FormatNotSupported;
|
||||
#endif
|
||||
|
||||
return noErr;
|
||||
}
|
||||
else
|
||||
jassertfalse;
|
||||
getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet);
|
||||
|
||||
return kAudioUnitErr_InvalidElement;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1063,14 +1039,13 @@ public:
|
|||
bool CanScheduleParameters() const override { return false; }
|
||||
|
||||
//==============================================================================
|
||||
ComponentResult Version() override { return JucePlugin_VersionCode; }
|
||||
bool SupportsTail() override { return true; }
|
||||
Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); }
|
||||
|
||||
double getSampleRate()
|
||||
{
|
||||
if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0)
|
||||
return GetOutput (0)->GetStreamFormat().mSampleRate;
|
||||
return Output (0).GetStreamFormat().mSampleRate;
|
||||
|
||||
return 44100.0;
|
||||
}
|
||||
|
|
@ -1236,14 +1211,16 @@ public:
|
|||
return ((! IsInitialized()) && (info.error == noErr));
|
||||
}
|
||||
|
||||
bool ValidFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& format) override
|
||||
bool ValidFormat (AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
const AudioStreamBasicDescription& inNewFormat) override
|
||||
{
|
||||
// DSP Quattro incorrectly uses global scope for the ValidFormat call
|
||||
if (scope == kAudioUnitScope_Global)
|
||||
return ValidFormat (kAudioUnitScope_Input, element, format)
|
||||
|| ValidFormat (kAudioUnitScope_Output, element, format);
|
||||
if (inScope == kAudioUnitScope_Global)
|
||||
return ValidFormat (kAudioUnitScope_Input, inElement, inNewFormat)
|
||||
|| ValidFormat (kAudioUnitScope_Output, inElement, inNewFormat);
|
||||
|
||||
const auto info = getElementInfo (scope, element);
|
||||
const auto info = getElementInfo (inScope, inElement);
|
||||
|
||||
if (info.error != noErr)
|
||||
return false;
|
||||
|
|
@ -1251,15 +1228,15 @@ public:
|
|||
if (info.kind == BusKind::wrapperOnly)
|
||||
return true;
|
||||
|
||||
const int newNumChannels = static_cast<int> (format.NumberChannels());
|
||||
const int oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr);
|
||||
const auto newNumChannels = static_cast<int> (inNewFormat.mChannelsPerFrame);
|
||||
const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr);
|
||||
|
||||
if (newNumChannels == oldNumChannels)
|
||||
return true;
|
||||
|
||||
if (AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr))
|
||||
{
|
||||
if (! MusicDeviceBase::ValidFormat (scope, element, format))
|
||||
if (! MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat))
|
||||
return false;
|
||||
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
|
|
@ -1276,17 +1253,20 @@ public:
|
|||
}
|
||||
|
||||
// AU requires us to override this for the sole reason that we need to find a default layout tag if the number of channels have changed
|
||||
OSStatus ChangeStreamFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& old, const CAStreamBasicDescription& format) override
|
||||
OSStatus ChangeStreamFormat (AudioUnitScope inScope,
|
||||
AudioUnitElement inElement,
|
||||
const AudioStreamBasicDescription& inPrevFormat,
|
||||
const AudioStreamBasicDescription& inNewFormat) override
|
||||
{
|
||||
const auto info = getElementInfo (scope, element);
|
||||
const auto info = getElementInfo (inScope, inElement);
|
||||
|
||||
if (info.error != noErr)
|
||||
return info.error;
|
||||
|
||||
AudioChannelLayoutTag& currentTag = getCurrentLayout (info.isInput, info.busNr);
|
||||
|
||||
const int newNumChannels = static_cast<int> (format.NumberChannels());
|
||||
const int oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr);
|
||||
const auto newNumChannels = static_cast<int> (inNewFormat.mChannelsPerFrame);
|
||||
const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr);
|
||||
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
|
||||
|
|
@ -1310,7 +1290,7 @@ public:
|
|||
if (set == AudioChannelSet())
|
||||
return kAudioUnitErr_FormatNotSupported;
|
||||
|
||||
const auto err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format);
|
||||
const auto err = MusicDeviceBase::ChangeStreamFormat (inScope, inElement, inPrevFormat, inNewFormat);
|
||||
|
||||
if (err == noErr)
|
||||
currentTag = CoreAudioLayouts::toCoreAudio (set);
|
||||
|
|
@ -1375,7 +1355,7 @@ public:
|
|||
for (int busIdx = 0; busIdx < numInputBuses; ++busIdx)
|
||||
{
|
||||
if (pulledSucceeded[busIdx])
|
||||
audioBuffer.set (busIdx, GetInput ((UInt32) busIdx)->GetBufferList(), mapper.get (true, busIdx));
|
||||
audioBuffer.set (busIdx, Input ((UInt32) busIdx).GetBufferList(), mapper.get (true, busIdx));
|
||||
else
|
||||
audioBuffer.clearInputBus (busIdx, (int) nFrames);
|
||||
}
|
||||
|
|
@ -1396,7 +1376,7 @@ public:
|
|||
// copy back
|
||||
{
|
||||
for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx)
|
||||
audioBuffer.get (busIdx, GetOutput ((UInt32) busIdx)->GetBufferList(), mapper.get (false, busIdx));
|
||||
audioBuffer.get (busIdx, Output ((UInt32) busIdx).GetBufferList(), mapper.get (false, busIdx));
|
||||
}
|
||||
|
||||
// process midi output
|
||||
|
|
@ -1415,10 +1395,10 @@ public:
|
|||
ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; }
|
||||
|
||||
//==============================================================================
|
||||
OSStatus HandleMidiEvent (UInt8 nStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override
|
||||
OSStatus HandleMIDIEvent (UInt8 inStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override
|
||||
{
|
||||
#if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect
|
||||
const juce::uint8 data[] = { (juce::uint8) (nStatus | inChannel),
|
||||
const juce::uint8 data[] = { (juce::uint8) (inStatus | inChannel),
|
||||
(juce::uint8) inData1,
|
||||
(juce::uint8) inData2 };
|
||||
|
||||
|
|
@ -1426,7 +1406,7 @@ public:
|
|||
incomingEvents.addEvent (data, 3, (int) inStartFrame);
|
||||
return noErr;
|
||||
#else
|
||||
ignoreUnused (nStatus, inChannel, inData1);
|
||||
ignoreUnused (inStatus, inChannel, inData1);
|
||||
ignoreUnused (inData2, inStartFrame);
|
||||
return kAudioUnitErr_PropertyNotInUse;
|
||||
#endif
|
||||
|
|
@ -1877,7 +1857,7 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
Array<AUChannelInfo> channelInfo;
|
||||
Array<Array<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts;
|
||||
Array<std::vector<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts;
|
||||
Array<AudioChannelLayoutTag> currentInputLayout, currentOutputLayout;
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1923,15 +1903,14 @@ private:
|
|||
|
||||
for (unsigned int i = 0; i < numInputBuses; ++i)
|
||||
{
|
||||
if (AUInputElement* input = GetInput (i))
|
||||
{
|
||||
const bool succeeded = (input->PullInput (flags, timestamp, i, nFrames) == noErr);
|
||||
auto& input = Input (i);
|
||||
|
||||
if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded)
|
||||
AudioUnitHelpers::clearAudioBuffer (input->GetBufferList());
|
||||
const bool succeeded = (input.PullInput (flags, timestamp, i, nFrames) == noErr);
|
||||
|
||||
pulledSucceeded[i] = succeeded;
|
||||
}
|
||||
if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded)
|
||||
AudioUnitHelpers::clearAudioBuffer (input.GetBufferList());
|
||||
|
||||
pulledSucceeded[i] = succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1942,13 +1921,13 @@ private:
|
|||
|
||||
for (UInt32 busIdx = 0; busIdx < numWrapperBuses; ++busIdx)
|
||||
{
|
||||
AUOutputElement* output = GetOutput (busIdx);
|
||||
auto& output = Output (busIdx);
|
||||
|
||||
if (output->WillAllocateBuffer())
|
||||
output->PrepareBuffer (nFrames);
|
||||
if (output.WillAllocateBuffer())
|
||||
output.PrepareBuffer (nFrames);
|
||||
|
||||
if (busIdx >= (UInt32) numProcessorBuses)
|
||||
AudioUnitHelpers::clearAudioBuffer (output->GetBufferList());
|
||||
AudioUnitHelpers::clearAudioBuffer (output.GetBufferList());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2026,7 +2005,7 @@ private:
|
|||
|
||||
void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels)
|
||||
{
|
||||
AUIOElement* element = GetElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast<UInt32> (busIdx))->AsIOElement();
|
||||
auto* element = Element (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast<UInt32> (busIdx)).AsIOElement();
|
||||
jassert (element != nullptr);
|
||||
|
||||
bufferList = &element->GetBufferList();
|
||||
|
|
@ -2124,7 +2103,7 @@ private:
|
|||
|
||||
if (forceUseLegacyParamIDs)
|
||||
{
|
||||
Globals()->UseIndexedParameters (numParams);
|
||||
Globals()->UseIndexedParameters (static_cast<UInt32> (numParams));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2261,8 +2240,8 @@ private:
|
|||
const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true);
|
||||
const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false);
|
||||
|
||||
const int numInputElements = static_cast<int> (GetScope(kAudioUnitScope_Input). GetNumberOfElements());
|
||||
const int numOutputElements = static_cast<int> (GetScope(kAudioUnitScope_Output).GetNumberOfElements());
|
||||
const int numInputElements = static_cast<int> (GetScope (kAudioUnitScope_Input). GetNumberOfElements());
|
||||
const int numOutputElements = static_cast<int> (GetScope (kAudioUnitScope_Output).GetNumberOfElements());
|
||||
|
||||
AudioProcessor::BusesLayout requestedLayouts;
|
||||
for (int dir = 0; dir < 2; ++dir)
|
||||
|
|
@ -2274,8 +2253,8 @@ private:
|
|||
|
||||
for (int busIdx = 0; busIdx < n; ++busIdx)
|
||||
{
|
||||
const AUIOElement* element = (busIdx < numAUElements ? GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr);
|
||||
const int numChannels = (element != nullptr ? static_cast<int> (element->GetStreamFormat().NumberChannels()) : 0);
|
||||
const auto* element = (busIdx < numAUElements ? &IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr);
|
||||
const int numChannels = (element != nullptr ? static_cast<int> (element->NumberChannels()) : 0);
|
||||
|
||||
AudioChannelLayoutTag currentLayoutTag = isInput ? currentInputLayout[busIdx] : currentOutputLayout[busIdx];
|
||||
const int tagNumChannels = currentLayoutTag & 0xffff;
|
||||
|
|
@ -2314,20 +2293,12 @@ private:
|
|||
if (numChannels == 0)
|
||||
return noErr;
|
||||
|
||||
if (AUIOElement* element = GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr))
|
||||
{
|
||||
element->SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName()));
|
||||
auto& element = IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr);
|
||||
|
||||
CAStreamBasicDescription streamDescription;
|
||||
streamDescription.mSampleRate = getSampleRate();
|
||||
element.SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName()));
|
||||
|
||||
streamDescription.SetCanonical ((UInt32) numChannels, false);
|
||||
return element->SetStreamFormat (streamDescription);
|
||||
}
|
||||
else
|
||||
jassertfalse;
|
||||
|
||||
return kAudioUnitErr_InvalidElement;
|
||||
const auto streamDescription = ausdk::ASBD::CreateCommonFloat32 (getSampleRate(), (UInt32) numChannels);
|
||||
return element.SetStreamFormat (streamDescription);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -2355,14 +2326,16 @@ private:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
Array<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); }
|
||||
const Array<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); }
|
||||
std::vector<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); }
|
||||
const std::vector<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); }
|
||||
AudioChannelLayoutTag& getCurrentLayout (bool isInput, int bus) noexcept { return (isInput ? currentInputLayout : currentOutputLayout).getReference (bus); }
|
||||
AudioChannelLayoutTag getCurrentLayout (bool isInput, int bus) const noexcept { return (isInput ? currentInputLayout : currentOutputLayout)[bus]; }
|
||||
|
||||
//==============================================================================
|
||||
void addSupportedLayoutTagsForBus (bool isInput, int busNum, Array<AudioChannelLayoutTag>& tags)
|
||||
std::vector<AudioChannelLayoutTag> getSupportedLayoutTagsForBus (bool isInput, int busNum) const
|
||||
{
|
||||
std::set<AudioChannelLayoutTag> tags;
|
||||
|
||||
if (AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNum))
|
||||
{
|
||||
#ifndef JucePlugin_PreferredChannelConfigurations
|
||||
|
|
@ -2370,7 +2343,7 @@ private:
|
|||
|
||||
for (auto tag : knownTags)
|
||||
if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag)))
|
||||
tags.addIfNotAlreadyThere (tag);
|
||||
tags.insert (tag);
|
||||
#endif
|
||||
|
||||
// add discrete layout tags
|
||||
|
|
@ -2384,10 +2357,12 @@ private:
|
|||
tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch));
|
||||
#else
|
||||
if (bus->isLayoutSupported (AudioChannelSet::discreteChannels (ch)))
|
||||
tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch));
|
||||
tags.insert (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return std::vector<AudioChannelLayoutTag> (tags.begin(), tags.end());
|
||||
}
|
||||
|
||||
void addSupportedLayoutTagsForDirection (bool isInput)
|
||||
|
|
@ -2397,12 +2372,7 @@ private:
|
|||
auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput);
|
||||
|
||||
for (int busNr = 0; busNr < numBuses; ++busNr)
|
||||
{
|
||||
Array<AudioChannelLayoutTag> busLayouts;
|
||||
addSupportedLayoutTagsForBus (isInput, busNr, busLayouts);
|
||||
|
||||
layouts.add (busLayouts);
|
||||
}
|
||||
layouts.add (getSupportedLayoutTagsForBus (isInput, busNr));
|
||||
}
|
||||
|
||||
void addSupportedLayoutTags()
|
||||
|
|
@ -2425,10 +2395,10 @@ private:
|
|||
void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement)
|
||||
{
|
||||
if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName
|
||||
&& juceFilter != nullptr && mContextName != nullptr)
|
||||
&& juceFilter != nullptr && GetContextName() != nullptr)
|
||||
{
|
||||
AudioProcessor::TrackProperties props;
|
||||
props.name = String::fromCFString (mContextName);
|
||||
props.name = String::fromCFString (GetContextName());
|
||||
|
||||
juceFilter->updateTrackProperties (props);
|
||||
}
|
||||
|
|
@ -2444,48 +2414,17 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \
|
||||
extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \
|
||||
extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \
|
||||
{ \
|
||||
PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnit; \
|
||||
return ComponentEntryPoint<Class>::Dispatch (params, obj); \
|
||||
}
|
||||
|
||||
#if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect
|
||||
#define FACTORY_BASE_CLASS AUMIDIEffectFactory
|
||||
#define FACTORY_BASE_CLASS ausdk::AUMusicDeviceFactory
|
||||
#else
|
||||
#define FACTORY_BASE_CLASS AUBaseFactory
|
||||
#define FACTORY_BASE_CLASS ausdk::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); \
|
||||
}
|
||||
AUSDK_COMPONENT_ENTRY (FACTORY_BASE_CLASS, JuceAU)
|
||||
|
||||
#define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix)
|
||||
#define JUCE_FACTORY_ENTRY(Class, Name) JUCE_FACTORY_ENTRYX(Class, Name)
|
||||
#define JUCE_AU_ENTRY_POINT_NAME JUCE_CONCAT (JucePlugin_AUExportPrefix, Factory)
|
||||
|
||||
//==============================================================================
|
||||
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)
|
||||
#endif
|
||||
|
||||
#if ! JUCE_DISABLE_AU_FACTORY_ENTRY
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", "-Wzero-as-null-pointer-constant")
|
||||
|
||||
#include "CoreAudioUtilityClasses/AUPlugInDispatch.cpp"
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
#endif
|
||||
extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc);
|
||||
AUSDK_EXPORT extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc) { return JuceAUFactory (inDesc); }
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
File: AUResources.r
|
||||
Abstract: AUResources.r
|
||||
Version: 1.1
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AUResources.r
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
/* sample macro definitions -- all of these symbols must be defined
|
||||
#define RES_ID kHALOutputResID
|
||||
#define COMP_TYPE kAudioUnitComponentType
|
||||
#define COMP_SUBTYPE kAudioUnitOutputSubType
|
||||
#define COMP_MANUF kAudioUnitAudioHardwareOutputSubSubType
|
||||
#define VERSION 0x00010000
|
||||
#define NAME "AudioHALOutput"
|
||||
#define DESCRIPTION "Audio hardware output AudioUnit"
|
||||
#define ENTRY_POINT "AUHALEntry"
|
||||
*/
|
||||
#define UseExtendedThingResource 1
|
||||
|
||||
#include <CoreServices/CoreServices.r>
|
||||
|
||||
// this is a define used to indicate that a component has no static data that would mean
|
||||
// that no more than one instance could be open at a time - never been true for AUs
|
||||
#ifndef cmpThreadSafeOnMac
|
||||
#define cmpThreadSafeOnMac 0x10000000
|
||||
#endif
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
resource 'STR ' (RES_ID, purgeable) {
|
||||
NAME
|
||||
};
|
||||
|
||||
resource 'STR ' (RES_ID + 1, purgeable) {
|
||||
DESCRIPTION
|
||||
};
|
||||
|
||||
resource 'dlle' (RES_ID) {
|
||||
ENTRY_POINT
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
resource 'thng' (RES_ID, NAME) {
|
||||
COMP_TYPE,
|
||||
COMP_SUBTYPE,
|
||||
COMP_MANUF,
|
||||
0, 0, 0, 0, // no 68K
|
||||
'STR ', RES_ID,
|
||||
'STR ', RES_ID + 1,
|
||||
0, 0, /* icon */
|
||||
VERSION,
|
||||
componentHasMultiplePlatforms | componentDoAutoVersion,
|
||||
0,
|
||||
{
|
||||
#if defined(ppc_YES)
|
||||
cmpThreadSafeOnMac,
|
||||
'dlle', RES_ID, platformPowerPCNativeEntryPoint
|
||||
#define NeedLeadingComma 1
|
||||
#endif
|
||||
#if defined(ppc64_YES)
|
||||
#if defined(NeedLeadingComma)
|
||||
,
|
||||
#endif
|
||||
cmpThreadSafeOnMac,
|
||||
'dlle', RES_ID, platformPowerPC64NativeEntryPoint
|
||||
#define NeedLeadingComma 1
|
||||
#endif
|
||||
#if defined(i386_YES)
|
||||
#if defined(NeedLeadingComma)
|
||||
,
|
||||
#endif
|
||||
cmpThreadSafeOnMac,
|
||||
'dlle', RES_ID, platformIA32NativeEntryPoint
|
||||
#define NeedLeadingComma 1
|
||||
#endif
|
||||
#if defined(x86_64_YES)
|
||||
#if defined(NeedLeadingComma)
|
||||
,
|
||||
#endif
|
||||
cmpThreadSafeOnMac,
|
||||
'dlle', RES_ID, 8
|
||||
#define NeedLeadingComma 1
|
||||
#endif
|
||||
// JUCE CHANGE STARTS HERE
|
||||
#if defined(arm64_YES)
|
||||
#if defined(NeedLeadingComma)
|
||||
,
|
||||
#endif
|
||||
cmpThreadSafeOnMac,
|
||||
'dlle', RES_ID, 9
|
||||
#define NeedLeadingComma 1
|
||||
#endif
|
||||
// JUCE CHANGE ENDS HERE
|
||||
}
|
||||
};
|
||||
|
||||
#undef RES_ID
|
||||
#undef COMP_TYPE
|
||||
#undef COMP_SUBTYPE
|
||||
#undef COMP_MANUF
|
||||
#undef VERSION
|
||||
#undef NAME
|
||||
#undef DESCRIPTION
|
||||
#undef ENTRY_POINT
|
||||
#undef NeedLeadingComma
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#define UseExtendedThingResource 1
|
||||
#include <AudioUnit.r>
|
||||
|
||||
//==============================================================================
|
||||
/* The JucePluginDefines file should be a file in your project, containing info to describe the
|
||||
plugin's name, type, etc. The Projucer will generate this file automatically for you.
|
||||
|
||||
You may need to adjust the include path of your project to make sure it can be
|
||||
found by this include statement. (Don't hack this file to change the include path)
|
||||
*/
|
||||
#include "JucePluginDefines.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// component resources for Audio Unit
|
||||
#define RES_ID 1000
|
||||
#define COMP_TYPE JucePlugin_AUMainType
|
||||
#define COMP_SUBTYPE JucePlugin_AUSubType
|
||||
#define COMP_MANUF JucePlugin_AUManufacturerCode
|
||||
#define VERSION JucePlugin_VersionCode
|
||||
#define NAME JucePlugin_Manufacturer ": " JucePlugin_Name
|
||||
#define DESCRIPTION JucePlugin_Desc
|
||||
#define ENTRY_POINT JucePlugin_AUExportPrefixQuoted "Entry"
|
||||
|
||||
#include "AUResources.r"
|
||||
|
|
@ -60,21 +60,42 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wparentheses",
|
|||
#define verify_noerr(errorCode) __Verify_noErr(errorCode)
|
||||
#endif
|
||||
|
||||
#include "AU/CoreAudioUtilityClasses/AUBase.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUBuffer.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUDispatch.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUInputElement.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUMIDIBase.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUOutputBase.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUOutputElement.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/AUScopeElement.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/CAAUParameter.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/CAMutex.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/CAVectorUnit.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/ComponentBase.cpp"
|
||||
#include "AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp"
|
||||
#if ! defined (MAC_OS_VERSION_11_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0
|
||||
// These constants are only defined in the macOS 11+ SDKs
|
||||
|
||||
enum MIDICVStatus : unsigned int
|
||||
{
|
||||
kMIDICVStatusNoteOff = 0x8,
|
||||
kMIDICVStatusNoteOn = 0x9,
|
||||
kMIDICVStatusPolyPressure = 0xA,
|
||||
kMIDICVStatusControlChange = 0xB,
|
||||
kMIDICVStatusProgramChange = 0xC,
|
||||
kMIDICVStatusChannelPressure = 0xD,
|
||||
kMIDICVStatusPitchBend = 0xE,
|
||||
kMIDICVStatusRegisteredPNC = 0x0,
|
||||
kMIDICVStatusAssignablePNC = 0x1,
|
||||
kMIDICVStatusRegisteredControl = 0x2,
|
||||
kMIDICVStatusAssignableControl = 0x3,
|
||||
kMIDICVStatusRelRegisteredControl = 0x4,
|
||||
kMIDICVStatusRelAssignableControl = 0x5,
|
||||
kMIDICVStatusPerNotePitchBend = 0x6,
|
||||
kMIDICVStatusPerNoteMgmt = 0xF
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#include "AU/AudioUnitSDK/AUBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUBuffer.cpp"
|
||||
#include "AU/AudioUnitSDK/AUBufferAllocator.cpp"
|
||||
#include "AU/AudioUnitSDK/AUEffectBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUInputElement.cpp"
|
||||
#include "AU/AudioUnitSDK/AUMIDIBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUMIDIEffectBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUOutputElement.cpp"
|
||||
#include "AU/AudioUnitSDK/AUPlugInDispatch.cpp"
|
||||
#include "AU/AudioUnitSDK/AUScopeElement.cpp"
|
||||
#include "AU/AudioUnitSDK/ComponentBase.cpp"
|
||||
#include "AU/AudioUnitSDK/MusicDeviceBase.cpp"
|
||||
|
||||
#undef verify
|
||||
#undef verify_noerr
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue