From fea2cba24bfa88fb8ae1216f59be283becae92af Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 15 Aug 2020 11:48:40 +1000 Subject: [PATCH] Add support for offsets to the low-level mixing API. --- research/ma_mixing.h | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/research/ma_mixing.h b/research/ma_mixing.h index 7796790d..d9c10f4e 100644 --- a/research/ma_mixing.h +++ b/research/ma_mixing.h @@ -599,7 +599,7 @@ ma_mixer_mix_pcm_frames() ma_mixer_begin() ma_mixer_end() */ -MA_API ma_result ma_mixer_mix_pcm_frames(ma_mixer* pMixer, const void* pFramesIn, ma_uint64 frameCountIn, float volume, ma_format formatIn, ma_uint32 channelsIn); +MA_API ma_result ma_mixer_mix_pcm_frames(ma_mixer* pMixer, const void* pFramesIn, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, float volume, ma_format formatIn, ma_uint32 channelsIn); /* Mixes audio data from a data source @@ -645,9 +645,9 @@ See Also ma_mixer_begin() ma_mixer_end() */ -MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_bool32 loop); -MA_API ma_result ma_mixer_mix_rb(ma_mixer* pMixer, ma_rb* pRB, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn); /* Caller is the consumer. */ -MA_API ma_result ma_mixer_mix_pcm_rb(ma_mixer* pMixer, ma_pcm_rb* pRB, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect); /* Caller is the consumer. */ +MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_bool32 loop); +MA_API ma_result ma_mixer_mix_rb(ma_mixer* pMixer, ma_rb* pRB, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn); /* Caller is the consumer. */ +MA_API ma_result ma_mixer_mix_pcm_rb(ma_mixer* pMixer, ma_pcm_rb* pRB, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect); /* Caller is the consumer. */ MA_API ma_result ma_mixer_set_volume(ma_mixer* pMixer, float volume); MA_API ma_result ma_mixer_get_volume(ma_mixer* pMixer, float* pVolume); @@ -2463,7 +2463,7 @@ MA_API ma_result ma_mixer_end(ma_mixer* pMixer, ma_mixer* pParentMixer, void* pF return MA_SUCCESS; } -MA_API ma_result ma_mixer_mix_pcm_frames(ma_mixer* pMixer, const void* pFramesIn, ma_uint64 frameCountIn, float volume, ma_format formatIn, ma_uint32 channelsIn) +MA_API ma_result ma_mixer_mix_pcm_frames(ma_mixer* pMixer, const void* pFramesIn, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, float volume, ma_format formatIn, ma_uint32 channelsIn) { if (pMixer == NULL || pFramesIn == NULL) { return MA_INVALID_ARGS; @@ -2473,16 +2473,16 @@ MA_API ma_result ma_mixer_mix_pcm_frames(ma_mixer* pMixer, const void* pFramesIn return MA_INVALID_ARGS; /* Passing in too many input frames. */ } - ma_mix_pcm_frames(pMixer->pAccumulationBuffer, pFramesIn, frameCountIn, formatIn, channelsIn, volume); + ma_mix_pcm_frames(ma_offset_ptr(pMixer->pAccumulationBuffer, offsetInFrames * ma_get_accumulation_bytes_per_frame(pMixer->format, pMixer->channels)), pFramesIn, frameCountIn, formatIn, channelsIn, volume); return MA_SUCCESS; } -static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn, ma_bool32 loop) +static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn, ma_bool32 loop) { ma_result result = MA_SUCCESS; ma_uint64 totalFramesProcessed = 0; - void* pRunningAccumulationBuffer = pMixer->pAccumulationBuffer; + void* pRunningAccumulationBuffer = NULL; ma_bool32 preEffectConversionRequired = MA_FALSE; ma_format effectFormatIn = ma_format_unknown; ma_uint32 effectChannelsIn = 0; @@ -2496,10 +2496,13 @@ static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source* *pFrameCountOut = 0; } - if (frameCountIn > pMixer->mixingState.frameCountIn) { + if ((offsetInFrames + frameCountIn) > pMixer->mixingState.frameCountIn) { return MA_INVALID_ARGS; /* Passing in too many input frames. */ } + /* Initially offset the accumulation buffer by the offset. */ + pRunningAccumulationBuffer = ma_offset_ptr(pMixer->pAccumulationBuffer, offsetInFrames * ma_get_accumulation_bytes_per_frame(pMixer->format, pMixer->channels)); + if (pEffect != NULL) { /* We need to know the effect's input and output data format before we'll be able to apply it properly. */ result = ma_effect_get_input_data_format(pEffect, &effectFormatIn, &effectChannelsIn, NULL); @@ -2597,7 +2600,7 @@ static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source* return result; } -static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn, ma_bool32 loop) +static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn, ma_bool32 loop) { ma_result result = MA_SUCCESS; ma_uint8 preMixBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; @@ -2617,7 +2620,7 @@ static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source* *pFrameCountOut = 0; } - if (frameCountIn > pMixer->mixingState.frameCountIn) { + if ((offsetInFrames + frameCountIn) > pMixer->mixingState.frameCountIn) { return MA_INVALID_ARGS; /* Passing in too many input frames. */ } @@ -2642,7 +2645,9 @@ static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source* preMixBufferCap = sizeof(preMixBuffer) / ma_get_bytes_per_frame(preMixFormat, preMixChannels); totalFramesProcessed = 0; - pRunningAccumulationBuffer = pMixer->pAccumulationBuffer; + + /* Initially offset the accumulation buffer by the offset. */ + pRunningAccumulationBuffer = ma_offset_ptr(pMixer->pAccumulationBuffer, offsetInFrames * ma_get_accumulation_bytes_per_frame(pMixer->format, pMixer->channels)); while (totalFramesProcessed < frameCountIn) { ma_uint64 framesRead; @@ -2714,7 +2719,7 @@ static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source* return result; } -MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_bool32 loop) +MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_bool32 loop) { ma_result result; ma_format formatIn; @@ -2738,10 +2743,10 @@ MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDat if (supportsMMap) { /* Fast path. This is memory mapping mode. */ - return ma_mixer_mix_data_source_mmap(pMixer, pDataSourceCallbacks, frameCountIn, pFrameCountOut, volume, pEffect, formatIn, channelsIn, loop); + return ma_mixer_mix_data_source_mmap(pMixer, pDataSourceCallbacks, offsetInFrames, frameCountIn, pFrameCountOut, volume, pEffect, formatIn, channelsIn, loop); } else { /* Slow path. This is reading mode. */ - return ma_mixer_mix_data_source_read(pMixer, pDataSourceCallbacks, frameCountIn, pFrameCountOut, volume, pEffect, formatIn, channelsIn, loop); + return ma_mixer_mix_data_source_read(pMixer, pDataSourceCallbacks, offsetInFrames, frameCountIn, pFrameCountOut, volume, pEffect, formatIn, channelsIn, loop); } } @@ -2815,18 +2820,18 @@ static ma_result ma_rb_data_source_init(ma_rb* pRB, ma_format format, ma_uint32 return MA_SUCCESS; } -MA_API ma_result ma_mixer_mix_rb(ma_mixer* pMixer, ma_rb* pRB, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn) +MA_API ma_result ma_mixer_mix_rb(ma_mixer* pMixer, ma_rb* pRB, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn) { /* Ring buffer mixing can be implemented in terms of a memory mapped data source. */ ma_rb_data_source ds; ma_rb_data_source_init(pRB, formatIn, channelsIn, &ds); /* Will never fail and does not require an uninit() implementation. */ - return ma_mixer_mix_data_source(pMixer, &ds, frameCountIn, pFrameCountOut, volume, pEffect, MA_TRUE); /* Ring buffers always loop, but the loop parameter will never actually be used because ma_rb_data_source__on_unmap() will never return MA_AT_END. */ + return ma_mixer_mix_data_source(pMixer, &ds, offsetInFrames, frameCountIn, pFrameCountOut, volume, pEffect, MA_TRUE); /* Ring buffers always loop, but the loop parameter will never actually be used because ma_rb_data_source__on_unmap() will never return MA_AT_END. */ } -MA_API ma_result ma_mixer_mix_pcm_rb(ma_mixer* pMixer, ma_pcm_rb* pRB, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect) +MA_API ma_result ma_mixer_mix_pcm_rb(ma_mixer* pMixer, ma_pcm_rb* pRB, ma_uint64 offsetInFrames, ma_uint64 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect) { - return ma_mixer_mix_rb(pMixer, &pRB->rb, frameCountIn, pFrameCountOut, volume, pEffect, pRB->format, pRB->channels); + return ma_mixer_mix_rb(pMixer, &pRB->rb, offsetInFrames, frameCountIn, pFrameCountOut, volume, pEffect, pRB->format, pRB->channels); }