| 
							- /*!
 - 	@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
 
 
  |