Add output parameter for number of frames mixed to ma_mixer_mix_*().

This commit is contained in:
David Reid
2020-08-09 08:59:49 +10:00
parent 0672f3043a
commit 65e547c5a6
3 changed files with 45 additions and 24 deletions
+3 -2
View File
@@ -37,7 +37,7 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin
{ {
size_t iDataSource; size_t iDataSource;
for (iDataSource = 0; iDataSource < g_dataSourceCount; iDataSource += 1) { for (iDataSource = 0; iDataSource < g_dataSourceCount; iDataSource += 1) {
ma_mixer_mix_data_source(&g_mixer, &g_dataSources[iDataSource], frameCountIn, 1, NULL, MA_TRUE); ma_mixer_mix_data_source(&g_mixer, &g_dataSources[iDataSource], frameCountIn, NULL, 1, NULL, MA_TRUE);
} }
} }
ma_mixer_end(&g_mixer, NULL, ma_offset_ptr(pOutput, framesProcessed * bpf)); ma_mixer_end(&g_mixer, NULL, ma_offset_ptr(pOutput, framesProcessed * bpf));
@@ -182,6 +182,7 @@ int main(int argc, char** argv)
&resourceManager, &resourceManager,
argv[iFile+1], argv[iFile+1],
MA_DATA_SOURCE_FLAG_DECODE | MA_DATA_SOURCE_FLAG_ASYNC /*| MA_DATA_SOURCE_FLAG_STREAM*/, MA_DATA_SOURCE_FLAG_DECODE | MA_DATA_SOURCE_FLAG_ASYNC /*| MA_DATA_SOURCE_FLAG_STREAM*/,
NULL, /* Async notification. */
&g_dataSources[iFile]); &g_dataSources[iFile]);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
@@ -212,7 +213,7 @@ int main(int argc, char** argv)
/* Our data sources need to be explicitly uninitialized. ma_resource_manager_uninit() will not do it for us. */ /* Our data sources need to be explicitly uninitialized. ma_resource_manager_uninit() will not do it for us. */
for (iFile = 0; (size_t)iFile < g_dataSourceCount; iFile += 1) { for (iFile = 0; (size_t)iFile < g_dataSourceCount; iFile += 1) {
ma_resource_manager_data_source_uninit(&resourceManager, &g_dataSources[iFile]); ma_resource_manager_data_source_uninit(&g_dataSources[iFile]);
} }
/* Uninitialize the resource manager after each data source. */ /* Uninitialize the resource manager after each data source. */
+3 -2
View File
@@ -4980,6 +4980,7 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s
{ {
if (pSound->isPlaying) { if (pSound->isPlaying) {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_uint64 framesProcessed;
/* If the pitch has changed we need to update the resampler. */ /* If the pitch has changed we need to update the resampler. */
if (pSound->effect.oldPitch != pSound->effect.pitch) { if (pSound->effect.oldPitch != pSound->effect.pitch) {
@@ -4998,10 +4999,10 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s
effect we need to make sure we run it through the mixer because it may require us to update internal state for things like echo effects. effect we need to make sure we run it through the mixer because it may require us to update internal state for things like echo effects.
*/ */
if (pSound->volume > 0 || ma_engine_effect_is_passthrough(&pSound->effect) == MA_FALSE) { if (pSound->volume > 0 || ma_engine_effect_is_passthrough(&pSound->effect) == MA_FALSE) {
result = ma_mixer_mix_data_source(&pGroup->mixer, pSound->pDataSource, frameCount, pSound->volume, &pSound->effect, pSound->isLooping); result = ma_mixer_mix_data_source(&pGroup->mixer, pSound->pDataSource, frameCount, &framesProcessed, pSound->volume, &pSound->effect, pSound->isLooping);
} else { } else {
/* The sound is muted. We want to move time forward, but it be made faster by simply seeking instead of reading. We also want to bypass mixing completely. */ /* The sound is muted. We want to move time forward, but it be made faster by simply seeking instead of reading. We also want to bypass mixing completely. */
result = ma_data_source_seek_pcm_frames(pSound->pDataSource, frameCount, NULL, pSound->isLooping); result = ma_data_source_seek_pcm_frames(pSound->pDataSource, frameCount, &framesProcessed, pSound->isLooping);
} }
/* If fading out we need to stop the sound if it's done fading. */ /* If fading out we need to stop the sound if it's done fading. */
+39 -20
View File
@@ -617,6 +617,9 @@ frameCountIn (in)
The number of frames to mix. This cannot exceed the number of input frames returned by `ma_mixer_begin()`. If it does, an error will be returned. If it is The number of frames to mix. This cannot exceed the number of input frames returned by `ma_mixer_begin()`. If it does, an error will be returned. If it is
less, silence will be mixed to make up the excess. less, silence will be mixed to make up the excess.
pFrameCountOut (out)
Receives the number of frames that were processed from the data source.
formatIn (in) formatIn (in)
The sample format of the input data. The sample format of the input data.
@@ -642,9 +645,9 @@ See Also
ma_mixer_begin() ma_mixer_begin()
ma_mixer_end() ma_mixer_end()
*/ */
MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCountIn, 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 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, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn); /* Caller is the consumer. */ 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, float volume, ma_effect* pEffect); /* 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_set_volume(ma_mixer* pMixer, float volume); 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); MA_API ma_result ma_mixer_get_volume(ma_mixer* pMixer, float* pVolume);
@@ -2475,7 +2478,7 @@ MA_API ma_result ma_mixer_mix_pcm_frames(ma_mixer* pMixer, const void* pFramesIn
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCount, 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 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn, ma_bool32 loop)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_uint64 totalFramesProcessed = 0; ma_uint64 totalFramesProcessed = 0;
@@ -2489,7 +2492,11 @@ static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source*
MA_ASSERT(pMixer != NULL); MA_ASSERT(pMixer != NULL);
MA_ASSERT(pDataSource != NULL); MA_ASSERT(pDataSource != NULL);
if (frameCount > pMixer->mixingState.frameCountIn) { if (pFrameCountOut != NULL) {
*pFrameCountOut = 0;
}
if (frameCountIn > pMixer->mixingState.frameCountIn) {
return MA_INVALID_ARGS; /* Passing in too many input frames. */ return MA_INVALID_ARGS; /* Passing in too many input frames. */
} }
@@ -2508,9 +2515,9 @@ static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source*
preEffectConversionRequired = (formatIn != effectFormatIn || channelsIn != effectChannelsIn); preEffectConversionRequired = (formatIn != effectFormatIn || channelsIn != effectChannelsIn);
} }
while (totalFramesProcessed < frameCount) { while (totalFramesProcessed < frameCountIn) {
void* pMappedBuffer; void* pMappedBuffer;
ma_uint64 framesToProcess = frameCount - totalFramesProcessed; ma_uint64 framesToProcess = frameCountIn - totalFramesProcessed;
if (pEffect == NULL) { if (pEffect == NULL) {
/* Fast path. Mix directly from the data source and don't bother applying an effect. */ /* Fast path. Mix directly from the data source and don't bother applying an effect. */
@@ -2546,7 +2553,7 @@ static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source*
/* We need to map our input data first. The input data will be either fed directly into the effect, or will be converted first. */ /* We need to map our input data first. The input data will be either fed directly into the effect, or will be converted first. */
result = ma_data_source_map(pDataSource, &pMappedBuffer, &framesMapped); result = ma_data_source_map(pDataSource, &pMappedBuffer, &framesMapped);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; break; /* Failed to map. Abort. */
} }
/* We have the data from the data source so no we can apply the effect. */ /* We have the data from the data source so no we can apply the effect. */
@@ -2578,15 +2585,19 @@ static ma_result ma_mixer_mix_data_source_mmap(ma_mixer* pMixer, ma_data_source*
break; /* We've reached the end and we're not looping. */ break; /* We've reached the end and we're not looping. */
} }
} else { } else {
return result; /* An error occurred. */ break; /* An error occurred. */
} }
} }
} }
if (pFrameCountOut != NULL) {
*pFrameCountOut = totalFramesProcessed;
}
return result; return result;
} }
static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCount, 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 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_format formatIn, ma_uint32 channelsIn, ma_bool32 loop)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_uint8 preMixBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint8 preMixBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
@@ -2602,7 +2613,11 @@ static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source*
MA_ASSERT(pMixer != NULL); MA_ASSERT(pMixer != NULL);
MA_ASSERT(pDataSource != NULL); MA_ASSERT(pDataSource != NULL);
if (frameCount > pMixer->mixingState.frameCountIn) { if (pFrameCountOut != NULL) {
*pFrameCountOut = 0;
}
if (frameCountIn > pMixer->mixingState.frameCountIn) {
return MA_INVALID_ARGS; /* Passing in too many input frames. */ return MA_INVALID_ARGS; /* Passing in too many input frames. */
} }
@@ -2629,9 +2644,9 @@ static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source*
totalFramesProcessed = 0; totalFramesProcessed = 0;
pRunningAccumulationBuffer = pMixer->pAccumulationBuffer; pRunningAccumulationBuffer = pMixer->pAccumulationBuffer;
while (totalFramesProcessed < frameCount) { while (totalFramesProcessed < frameCountIn) {
ma_uint64 framesRead; ma_uint64 framesRead;
ma_uint64 framesToRead = frameCount - totalFramesProcessed; ma_uint64 framesToRead = frameCountIn - totalFramesProcessed;
if (framesToRead > preMixBufferCap) { if (framesToRead > preMixBufferCap) {
framesToRead = preMixBufferCap; framesToRead = preMixBufferCap;
} }
@@ -2692,10 +2707,14 @@ static ma_result ma_mixer_mix_data_source_read(ma_mixer* pMixer, ma_data_source*
} }
} }
if (pFrameCountOut != NULL) {
*pFrameCountOut = totalFramesProcessed;
}
return result; return result;
} }
MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDataSource, ma_uint64 frameCountIn, 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 frameCountIn, ma_uint64* pFrameCountOut, float volume, ma_effect* pEffect, ma_bool32 loop)
{ {
ma_result result; ma_result result;
ma_format formatIn; ma_format formatIn;
@@ -2719,10 +2738,10 @@ MA_API ma_result ma_mixer_mix_data_source(ma_mixer* pMixer, ma_data_source* pDat
if (supportsMMap) { if (supportsMMap) {
/* Fast path. This is memory mapping mode. */ /* Fast path. This is memory mapping mode. */
return ma_mixer_mix_data_source_mmap(pMixer, pDataSourceCallbacks, frameCountIn, volume, pEffect, formatIn, channelsIn, loop); return ma_mixer_mix_data_source_mmap(pMixer, pDataSourceCallbacks, frameCountIn, pFrameCountOut, volume, pEffect, formatIn, channelsIn, loop);
} else { } else {
/* Slow path. This is reading mode. */ /* Slow path. This is reading mode. */
return ma_mixer_mix_data_source_read(pMixer, pDataSourceCallbacks, frameCountIn, volume, pEffect, formatIn, channelsIn, loop); return ma_mixer_mix_data_source_read(pMixer, pDataSourceCallbacks, frameCountIn, pFrameCountOut, volume, pEffect, formatIn, channelsIn, loop);
} }
} }
@@ -2796,18 +2815,18 @@ static ma_result ma_rb_data_source_init(ma_rb* pRB, ma_format format, ma_uint32
return MA_SUCCESS; return MA_SUCCESS;
} }
MA_API ma_result ma_mixer_mix_rb(ma_mixer* pMixer, ma_rb* pRB, ma_uint64 frameCountIn, 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 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. */ /* Ring buffer mixing can be implemented in terms of a memory mapped data source. */
ma_rb_data_source ds; ma_rb_data_source ds;
ma_rb_data_source_init(pRB, formatIn, channelsIn, &ds); /* Will never fail and does not require an uninit() implementation. */ 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, 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, 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, float volume, ma_effect* pEffect) 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)
{ {
return ma_mixer_mix_rb(pMixer, &pRB->rb, frameCountIn, volume, pEffect, pRB->format, pRB->channels); return ma_mixer_mix_rb(pMixer, &pRB->rb, frameCountIn, pFrameCountOut, volume, pEffect, pRB->format, pRB->channels);
} }