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