Commit 75401a54 authored by David Reid's avatar David Reid

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.
parent ea545bc3
...@@ -361,17 +361,12 @@ struct ma_effect_base ...@@ -361,17 +361,12 @@ struct ma_effect_base
ma_uint64 (* onGetExpectedOutputFrameCount)(ma_effect* pEffect, ma_uint64 inputFrameCount); 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 (* 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_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(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_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_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_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_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); 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 ...@@ -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_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* 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) { if (pEffect == NULL || pBase->onProcessPCMFrames == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/* We need to start at the top and work our way down. */ return pBase->onProcessPCMFrames(pEffect, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
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;
} }
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_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 ...@@ -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_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) { if (pEffect == NULL) {
return 0; return 0;
} }
localInputFrameCount = ma_effect_get_required_input_frame_count_local(pEffect, outputFrameCount); return 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;
}
}
} }
static ma_uint64 ma_effect_get_expected_output_frame_count_local(ma_effect* pEffect, ma_uint64 inputFrameCount) 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 ...@@ -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_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) { if (pEffect == NULL) {
return 0; return 0;
} }
localOutputFrameCount = ma_effect_get_expected_output_frame_count_local(pEffect, inputFrameCount); return 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;
} }
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_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* ...@@ -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_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_result result;
ma_format format; ma_format format;
ma_uint32 channels; ma_uint32 channels;
...@@ -2202,12 +1956,7 @@ MA_API ma_result ma_effect_get_input_data_format(ma_effect* pEffect, ma_format* ...@@ -2202,12 +1956,7 @@ MA_API ma_result ma_effect_get_input_data_format(ma_effect* pEffect, ma_format*
*pSampleRate = 0; *pSampleRate = 0;
} }
pRootEffect = ma_effect_get_root(pEffect); result = pBase->onGetInputDataFormat(pEffect, &format, &channels, &sampleRate);
if (pRootEffect == NULL || pRootEffect->onGetInputDataFormat == NULL) {
return MA_INVALID_ARGS;
}
result = pRootEffect->onGetInputDataFormat(pRootEffect, &format, &channels, &sampleRate);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment