From 75401a5487ade08f0df51212ec8eee4d2b4cc8c3 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 14 Nov 2020 15:46:55 +1000 Subject: [PATCH] Remove effect chaining from the main ma_effect API. This is adding too much complexity, is less efficient than doing it manually, and is not compatible with some future changes for supporting effects that require multiple input streams. --- research/miniaudio_engine.h | 261 +----------------------------------- 1 file changed, 5 insertions(+), 256 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index f0e247aa..12c14384 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -361,17 +361,12 @@ struct ma_effect_base ma_uint64 (* onGetExpectedOutputFrameCount)(ma_effect* pEffect, ma_uint64 inputFrameCount); ma_result (* onGetInputDataFormat)(ma_effect* pEffect, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); ma_result (* onGetOutputDataFormat)(ma_effect* pEffect, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); - ma_effect_base* pPrev; - ma_effect_base* pNext; }; MA_API ma_result ma_effect_process_pcm_frames(ma_effect* pEffect, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); MA_API ma_result ma_effect_process_pcm_frames_with_conversion(ma_effect* pEffect, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut, ma_format formatIn, ma_uint32 channelsIn, ma_format formatOut, ma_uint32 channelsOut); MA_API ma_uint64 ma_effect_get_required_input_frame_count(ma_effect* pEffect, ma_uint64 outputFrameCount); MA_API ma_uint64 ma_effect_get_expected_output_frame_count(ma_effect* pEffect, ma_uint64 inputFrameCount); -MA_API ma_result ma_effect_append(ma_effect* pEffect, ma_effect* pParent); -MA_API ma_result ma_effect_prepend(ma_effect* pEffect, ma_effect* pChild); -MA_API ma_result ma_effect_detach(ma_effect* pEffect); MA_API ma_result ma_effect_get_output_data_format(ma_effect* pEffect, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); MA_API ma_result ma_effect_get_input_data_format(ma_effect* pEffect, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate); @@ -1761,147 +1756,15 @@ static void ma_convert_pcm_frames_format_and_channels(void* pDst, ma_format form } -static ma_effect_base* ma_effect_get_root(ma_effect* pEffect) -{ - ma_effect_base* pRootEffect; - - if (pEffect == NULL) { - return NULL; - } - - pRootEffect = (ma_effect_base*)pEffect; - for (;;) { - if (pRootEffect->pPrev == NULL) { - return pRootEffect; - } else { - pRootEffect = pRootEffect->pPrev; - } - } - - /* Should never hit this. */ - /*return NULL;*/ -} - MA_API ma_result ma_effect_process_pcm_frames(ma_effect* pEffect, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) { - ma_result result = MA_SUCCESS; ma_effect_base* pBase = (ma_effect_base*)pEffect; - ma_effect_base* pFirstEffect; - ma_effect_base* pRunningEffect; - ma_uint32 iTempBuffer = 0; - ma_uint8 tempFrames[2][MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; - ma_uint64 tempFrameCount[2]; - ma_uint64 frameCountIn; - ma_uint64 frameCountInConsumed; - ma_uint64 frameCountOut; - ma_uint64 frameCountOutConsumed; if (pEffect == NULL || pBase->onProcessPCMFrames == NULL) { return MA_INVALID_ARGS; } - /* We need to start at the top and work our way down. */ - pFirstEffect = (ma_effect_base*)pEffect; - while (pFirstEffect->pPrev != NULL) { - pFirstEffect = pFirstEffect->pPrev; - } - - pRunningEffect = pFirstEffect; - - /* Optimized path if this is the only effect in the chain. */ - if (pFirstEffect == pBase) { - return pBase->onProcessPCMFrames(pRunningEffect, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); - } - - frameCountIn = *pFrameCountIn; - frameCountInConsumed = 0; - frameCountOut = *pFrameCountOut; - frameCountOutConsumed = 0; - - /* - We need to output into a temp buffer which will become our new input buffer. We will allocate this on the stack which means we will need to do - several iterations to process as much data as possible available in the input buffer, or can fit in the output buffer. - */ - while (frameCountIn < frameCountInConsumed && frameCountOut < frameCountOutConsumed) { - for (;;) { - MA_ASSERT(pRunningEffect != NULL); - - const void* pRunningFramesIn; - /* */ void* pRunningFramesOut; - ma_uint64 frameCountInThisIteration; - ma_uint64 frameCountOutThisIteration; - ma_format runningEffectFormatIn; - ma_uint32 runningEffectChannelsIn; - - if (pRunningEffect->onGetInputDataFormat == NULL) { - result = MA_INVALID_ARGS; /* Don't have a way to retrieve the input format. */ - break; - } - - result = pRunningEffect->onGetInputDataFormat(pRunningEffect, &runningEffectFormatIn, &runningEffectChannelsIn, NULL); - if (result != MA_SUCCESS) { - return result; /* Failed to retrieve the input data format. Abort. */ - } - - - if (pRunningEffect == pFirstEffect) { - /* It's the first effect which means we need to read directly from the input buffer. */ - pRunningFramesIn = ma_offset_ptr(pFramesIn, frameCountInConsumed * ma_get_bytes_per_frame(runningEffectFormatIn, runningEffectChannelsIn)); - frameCountInThisIteration = frameCountIn - frameCountInConsumed; - } else { - /* It's not the first item. We need to read from a temp buffer. */ - pRunningFramesIn = tempFrames[iTempBuffer]; - frameCountInThisIteration = tempFrameCount[iTempBuffer]; - iTempBuffer = (iTempBuffer + 1) & 0x01; /* Toggle between 0 and 1. */ - } - - if (pRunningEffect == pEffect) { - /* It's the last item in the chain so we need to output directly to the output buffer. */ - pRunningFramesOut = ma_offset_ptr(pFramesOut, frameCountOutConsumed * ma_get_bytes_per_frame(runningEffectFormatIn, runningEffectChannelsIn)); - frameCountOutThisIteration = frameCountOut - frameCountOutConsumed; - } else { - /* It's not the last item in the chain. We need to output to a temp buffer so that it becomes our input buffer in the next iteration. */ - pRunningFramesOut = tempFrames[iTempBuffer]; - frameCountOutThisIteration = sizeof(tempFrames[iTempBuffer]) / ma_get_bytes_per_frame(runningEffectFormatIn, runningEffectChannelsIn); - } - - result = pRunningEffect->onProcessPCMFrames(pRunningEffect, pRunningFramesIn, &frameCountInThisIteration, pRunningFramesOut, &frameCountOutThisIteration); - if (result != MA_SUCCESS) { - break; - } - - /* - We need to increment our input and output frame counters. This depends on whether or not we read directly from the input buffer or wrote directly - to the output buffer. - */ - if (pRunningEffect == pFirstEffect) { - frameCountInConsumed += frameCountInThisIteration; - } - if (pRunningEffect == pBase) { - frameCountOutConsumed += frameCountOutThisIteration; - } - - tempFrameCount[iTempBuffer] = frameCountOutThisIteration; - - - /* If we just processed the input effect we need to abort. */ - if (pRunningEffect == pBase) { - break; - } - - pRunningEffect = pRunningEffect->pNext; - } - } - - - if (pFrameCountIn != NULL) { - *pFrameCountIn = frameCountInConsumed; - } - if (pFrameCountOut != NULL) { - *pFrameCountOut = frameCountOutConsumed; - } - - return result; + return pBase->onProcessPCMFrames(pEffect, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); } MA_API ma_result ma_effect_process_pcm_frames_with_conversion(ma_effect* pEffect, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut, ma_format formatIn, ma_uint32 channelsIn, ma_format formatOut, ma_uint32 channelsOut) @@ -2005,25 +1868,11 @@ static ma_uint64 ma_effect_get_required_input_frame_count_local(ma_effect* pEffe MA_API ma_uint64 ma_effect_get_required_input_frame_count(ma_effect* pEffect, ma_uint64 outputFrameCount) { - ma_effect_base* pBase = (ma_effect_base*)pEffect; - ma_uint64 localInputFrameCount; - if (pEffect == NULL) { return 0; } - localInputFrameCount = ma_effect_get_required_input_frame_count_local(pEffect, outputFrameCount); - - if (pBase->pPrev == NULL) { - return localInputFrameCount; - } else { - ma_uint64 parentInputFrameCount = ma_effect_get_required_input_frame_count(pBase->pPrev, outputFrameCount); - if (parentInputFrameCount > localInputFrameCount) { - return parentInputFrameCount; - } else { - return localInputFrameCount; - } - } + return ma_effect_get_required_input_frame_count_local(pEffect, outputFrameCount); } static ma_uint64 ma_effect_get_expected_output_frame_count_local(ma_effect* pEffect, ma_uint64 inputFrameCount) @@ -2042,106 +1891,11 @@ static ma_uint64 ma_effect_get_expected_output_frame_count_local(ma_effect* pEff MA_API ma_uint64 ma_effect_get_expected_output_frame_count(ma_effect* pEffect, ma_uint64 inputFrameCount) { - ma_effect_base* pBase = (ma_effect_base*)pEffect; - ma_uint64 localOutputFrameCount; - if (pEffect == NULL) { return 0; } - localOutputFrameCount = ma_effect_get_expected_output_frame_count_local(pEffect, inputFrameCount); - - if (pBase->pPrev == NULL) { - return localOutputFrameCount; - } else { - ma_uint64 parentOutputFrameCount = ma_effect_get_expected_output_frame_count(pBase->pPrev, inputFrameCount); - if (parentOutputFrameCount < localOutputFrameCount) { - return parentOutputFrameCount; - } else { - return localOutputFrameCount; - } - } -} - -ma_result ma_effect_append(ma_effect* pEffect, ma_effect* pParent) -{ - ma_effect_base* pBaseEffect = (ma_effect_base*)pEffect; - ma_effect_base* pBaseParent = (ma_effect_base*)pParent; - - if (pEffect == NULL || pParent == NULL || pEffect == pParent) { - return MA_INVALID_ARGS; - } - - /* The effect must be detached before reinserting into the list. */ - if (pBaseEffect->pPrev != NULL || pBaseEffect->pNext != NULL) { - return MA_INVALID_OPERATION; - } - - MA_ASSERT(pBaseEffect->pPrev == NULL); - MA_ASSERT(pBaseEffect->pNext == NULL); - - /* Update the effect first. */ - pBaseEffect->pPrev = pBaseParent; - pBaseEffect->pNext = pBaseParent->pNext; - - /* Now update the parent. Slot the effect between the parent and the parent's next item, if it has one. */ - if (pBaseParent->pNext != NULL) { - pBaseParent->pNext->pPrev = (ma_effect_base*)pEffect; - } - pBaseParent->pNext = (ma_effect_base*)pEffect; - - return MA_SUCCESS; -} - -ma_result ma_effect_prepend(ma_effect* pEffect, ma_effect* pChild) -{ - ma_effect_base* pBaseEffect = (ma_effect_base*)pEffect; - ma_effect_base* pBaseChild = (ma_effect_base*)pChild; - - if (pChild == NULL || pChild == NULL || pEffect == pChild) { - return MA_INVALID_ARGS; - } - - /* The effect must be detached before reinserting into the list. */ - if (pBaseEffect->pPrev != NULL || pBaseEffect->pNext != NULL) { - return MA_INVALID_OPERATION; - } - - MA_ASSERT(pBaseEffect->pPrev == NULL); - MA_ASSERT(pBaseEffect->pNext == NULL); - - /* Update the effect first. */ - pBaseEffect->pNext = pBaseChild; - pBaseEffect->pPrev = pBaseChild->pPrev; - - /* Now update the child. Slot the effect between the child and the child's previous item, if it has one. */ - if (pBaseChild->pPrev != NULL) { - pBaseChild->pPrev->pNext = (ma_effect_base*)pEffect; - } - pBaseChild->pPrev = (ma_effect_base*)pEffect; - - return MA_SUCCESS; -} - -ma_result ma_effect_detach(ma_effect* pEffect) -{ - ma_effect_base* pBaseEffect = (ma_effect_base*)pEffect; - - if (pBaseEffect == NULL) { - return MA_INVALID_ARGS; - } - - if (pBaseEffect->pPrev != NULL) { - pBaseEffect->pPrev->pNext = pBaseEffect->pNext; - pBaseEffect->pPrev = NULL; - } - - if (pBaseEffect->pNext != NULL) { - pBaseEffect->pNext->pPrev = pBaseEffect->pPrev; - pBaseEffect->pNext = NULL; - } - - return MA_SUCCESS; + return ma_effect_get_expected_output_frame_count_local(pEffect, inputFrameCount); } MA_API ma_result ma_effect_get_output_data_format(ma_effect* pEffect, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) @@ -2186,7 +1940,7 @@ MA_API ma_result ma_effect_get_output_data_format(ma_effect* pEffect, ma_format* MA_API ma_result ma_effect_get_input_data_format(ma_effect* pEffect, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate) { - ma_effect_base* pRootEffect; + ma_effect_base* pBase = (ma_effect_base*)pEffect; ma_result result; ma_format format; ma_uint32 channels; @@ -2202,12 +1956,7 @@ MA_API ma_result ma_effect_get_input_data_format(ma_effect* pEffect, ma_format* *pSampleRate = 0; } - pRootEffect = ma_effect_get_root(pEffect); - if (pRootEffect == NULL || pRootEffect->onGetInputDataFormat == NULL) { - return MA_INVALID_ARGS; - } - - result = pRootEffect->onGetInputDataFormat(pRootEffect, &format, &channels, &sampleRate); + result = pBase->onGetInputDataFormat(pEffect, &format, &channels, &sampleRate); if (result != MA_SUCCESS) { return result; }