Commit 8de49326 authored by David Reid's avatar David Reid

Add support for looping when reading data from data sources.

Updated APIs:
  * ma_data_source_read_pcm_frames()
  * ma_data_source_seek_pcm_frames()
parent 69253921
...@@ -5333,8 +5333,8 @@ typedef struct ...@@ -5333,8 +5333,8 @@ typedef struct
ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels); ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels);
} ma_data_source_callbacks; } ma_data_source_callbacks;
MA_API ma_uint64 ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ MA_API ma_uint64 ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
MA_API ma_uint64 ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */ MA_API ma_uint64 ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_bool32 loop); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */
MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex); MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex);
MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount); MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount);
MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */ MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
...@@ -39890,19 +39890,56 @@ MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format) ...@@ -39890,19 +39890,56 @@ MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format)
MA_API ma_uint64 ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount) MA_API ma_uint64 ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop)
{ {
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource; ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCallbacks == NULL || pCallbacks->onRead == NULL) { if (pCallbacks == NULL || pCallbacks->onRead == NULL) {
return 0; return 0;
} }
return pCallbacks->onRead(pDataSource, pFramesOut, frameCount); /* A very small optimization for the non looping case. */
if (loop == MA_FALSE) {
return pCallbacks->onRead(pDataSource, pFramesOut, frameCount);
} else {
ma_format format;
ma_uint32 channels;
if (ma_data_source_get_data_format(pDataSource, &format, &channels) != MA_SUCCESS) {
return pCallbacks->onRead(pDataSource, pFramesOut, frameCount); /* We don't have a way to retrieve the data format which means we don't know how to offset the output buffer. Just read as much as we can. */
} else {
ma_uint64 totalFramesProcessed;
void* pRunningFramesOut = pFramesOut;
totalFramesProcessed = 0;
while (totalFramesProcessed < frameCount) {
ma_uint64 framesProcessed;
ma_uint64 framesRemaining = frameCount - totalFramesProcessed;
framesProcessed = pCallbacks->onRead(pDataSource, pRunningFramesOut, framesRemaining);
totalFramesProcessed += framesProcessed;
/*
We can determine if we've reached the end by checking the return value of the onRead() callback. If it's less than what we requested it means
we've reached the end. To loop back to the start, all we need to do is seek back to the first frame.
*/
if (framesProcessed < framesRemaining) {
if (ma_data_source_seek_to_pcm_frame(pDataSource, 0) != MA_SUCCESS) {
break;
}
}
if (pRunningFramesOut != NULL) {
pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels));
}
}
return totalFramesProcessed;
}
}
} }
MA_API ma_uint64 ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount) MA_API ma_uint64 ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_bool32 loop)
{ {
return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, loop);
} }
MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex)
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