Commit 65e547c5 authored by David Reid's avatar David Reid

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

parent 0672f304
...@@ -37,7 +37,7 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin ...@@ -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) ...@@ -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) ...@@ -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. */
......
...@@ -4980,6 +4980,7 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s ...@@ -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 ...@@ -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. */
......
...@@ -617,6 +617,9 @@ frameCountIn (in) ...@@ -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 ...@@ -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 ...@@ -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* ...@@ -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* ...@@ -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* ...@@ -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* ...@@ -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* ...@@ -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* ...@@ -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* ...@@ -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 ...@@ -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 ...@@ -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);
} }
......
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