Commit adf18f2d authored by David Reid's avatar David Reid

Add support for data sources to self manage loop points and ranges.

This addresses an issue where data streams can have a delay between
loop points due to it's asynchronous loading mechanism. With this
change, streams should now have a clean loop transition.
parent bb4078cc
...@@ -8257,6 +8257,8 @@ Data Source ...@@ -8257,6 +8257,8 @@ Data Source
**************************************************************************************************/ **************************************************************************************************/
typedef void ma_data_source; typedef void ma_data_source;
#define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 0x00000001
typedef struct typedef struct
{ {
ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
...@@ -8265,6 +8267,7 @@ typedef struct ...@@ -8265,6 +8267,7 @@ typedef struct
ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor); ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor);
ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength); ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength);
ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping); ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping);
ma_uint32 flags;
} ma_data_source_vtable; } ma_data_source_vtable;
typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource); typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource);
...@@ -52241,8 +52244,8 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa ...@@ -52241,8 +52244,8 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
if (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE)) { if ((pDataSourceBase->vtable->flags & MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) != 0 || (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE))) {
/* No range is set - just read like normal. The data source itself will tell us when the end is reached. */ /* Either the data source is self-managing the range, or no range is set - just read like normal. The data source itself will tell us when the end is reached. */
result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
} else { } else {
/* Need to clamp to within the range. */ /* Need to clamp to within the range. */
...@@ -52867,7 +52870,8 @@ static ma_data_source_vtable g_ma_audio_buffer_ref_data_source_vtable = ...@@ -52867,7 +52870,8 @@ static ma_data_source_vtable g_ma_audio_buffer_ref_data_source_vtable =
ma_audio_buffer_ref__data_source_on_get_data_format, ma_audio_buffer_ref__data_source_on_get_data_format,
ma_audio_buffer_ref__data_source_on_get_cursor, ma_audio_buffer_ref__data_source_on_get_cursor,
ma_audio_buffer_ref__data_source_on_get_length, ma_audio_buffer_ref__data_source_on_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef) MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef)
...@@ -53550,7 +53554,8 @@ static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable = ...@@ -53550,7 +53554,8 @@ static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable =
ma_paged_audio_buffer__data_source_on_get_data_format, ma_paged_audio_buffer__data_source_on_get_data_format,
ma_paged_audio_buffer__data_source_on_get_cursor, ma_paged_audio_buffer__data_source_on_get_cursor,
ma_paged_audio_buffer__data_source_on_get_length, ma_paged_audio_buffer__data_source_on_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer) MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer)
...@@ -56139,7 +56144,8 @@ static ma_data_source_vtable g_ma_wav_ds_vtable = ...@@ -56139,7 +56144,8 @@ static ma_data_source_vtable g_ma_wav_ds_vtable =
ma_wav_ds_get_data_format, ma_wav_ds_get_data_format,
ma_wav_ds_get_cursor, ma_wav_ds_get_cursor,
ma_wav_ds_get_length, ma_wav_ds_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
...@@ -56781,7 +56787,8 @@ static ma_data_source_vtable g_ma_flac_ds_vtable = ...@@ -56781,7 +56787,8 @@ static ma_data_source_vtable g_ma_flac_ds_vtable =
ma_flac_ds_get_data_format, ma_flac_ds_get_data_format,
ma_flac_ds_get_cursor, ma_flac_ds_get_cursor,
ma_flac_ds_get_length, ma_flac_ds_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
...@@ -57416,7 +57423,8 @@ static ma_data_source_vtable g_ma_mp3_ds_vtable = ...@@ -57416,7 +57423,8 @@ static ma_data_source_vtable g_ma_mp3_ds_vtable =
ma_mp3_ds_get_data_format, ma_mp3_ds_get_data_format,
ma_mp3_ds_get_cursor, ma_mp3_ds_get_cursor,
ma_mp3_ds_get_length, ma_mp3_ds_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
...@@ -58104,7 +58112,8 @@ static ma_data_source_vtable g_ma_stbvorbis_ds_vtable = ...@@ -58104,7 +58112,8 @@ static ma_data_source_vtable g_ma_stbvorbis_ds_vtable =
ma_stbvorbis_ds_get_data_format, ma_stbvorbis_ds_get_data_format,
ma_stbvorbis_ds_get_cursor, ma_stbvorbis_ds_get_cursor,
ma_stbvorbis_ds_get_length, ma_stbvorbis_ds_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
...@@ -58860,7 +58869,8 @@ static ma_data_source_vtable g_ma_decoder_data_source_vtable = ...@@ -58860,7 +58869,8 @@ static ma_data_source_vtable g_ma_decoder_data_source_vtable =
ma_decoder__data_source_on_get_data_format, ma_decoder__data_source_on_get_data_format,
ma_decoder__data_source_on_get_cursor, ma_decoder__data_source_on_get_cursor,
ma_decoder__data_source_on_get_length, ma_decoder__data_source_on_get_length,
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, ma_decoder_tell_proc onTell, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder) static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, ma_decoder_tell_proc onTell, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
...@@ -60442,7 +60452,8 @@ static ma_data_source_vtable g_ma_waveform_data_source_vtable = ...@@ -60442,7 +60452,8 @@ static ma_data_source_vtable g_ma_waveform_data_source_vtable =
ma_waveform__data_source_on_get_data_format, ma_waveform__data_source_on_get_data_format,
ma_waveform__data_source_on_get_cursor, ma_waveform__data_source_on_get_cursor,
NULL, /* onGetLength. There's no notion of a length in waveforms. */ NULL, /* onGetLength. There's no notion of a length in waveforms. */
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform) MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform)
...@@ -60864,7 +60875,8 @@ static ma_data_source_vtable g_ma_noise_data_source_vtable = ...@@ -60864,7 +60875,8 @@ static ma_data_source_vtable g_ma_noise_data_source_vtable =
ma_noise__data_source_on_get_data_format, ma_noise__data_source_on_get_data_format,
NULL, /* onGetCursor. No notion of a cursor for noise. */ NULL, /* onGetCursor. No notion of a cursor for noise. */
NULL, /* onGetLength. No notion of a length for noise. */ NULL, /* onGetLength. No notion of a length for noise. */
NULL /* onSetLooping */ NULL, /* onSetLooping */
0
}; };
...@@ -63472,7 +63484,8 @@ static ma_data_source_vtable g_ma_resource_manager_data_buffer_vtable = ...@@ -63472,7 +63484,8 @@ static ma_data_source_vtable g_ma_resource_manager_data_buffer_vtable =
ma_resource_manager_data_buffer_cb__get_data_format, ma_resource_manager_data_buffer_cb__get_data_format,
ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames, ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames,
ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames, ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames,
ma_resource_manager_data_buffer_cb__set_looping ma_resource_manager_data_buffer_cb__set_looping,
0
}; };
static ma_result ma_resource_manager_data_buffer_init_internal(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, ma_uint64 initialSeekPoint, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer) static ma_result ma_resource_manager_data_buffer_init_internal(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, ma_uint64 initialSeekPoint, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer)
...@@ -64153,7 +64166,8 @@ static ma_data_source_vtable g_ma_resource_manager_data_stream_vtable = ...@@ -64153,7 +64166,8 @@ static ma_data_source_vtable g_ma_resource_manager_data_stream_vtable =
ma_resource_manager_data_stream_cb__get_data_format, ma_resource_manager_data_stream_cb__get_data_format,
ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames, ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames,
ma_resource_manager_data_stream_cb__get_length_in_pcm_frames, ma_resource_manager_data_stream_cb__get_length_in_pcm_frames,
ma_resource_manager_data_stream_cb__set_looping ma_resource_manager_data_stream_cb__set_looping,
MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT
}; };
static ma_result ma_resource_manager_data_stream_init_internal(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 flags, ma_uint64 initialSeekPoint, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream) static ma_result ma_resource_manager_data_stream_init_internal(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 flags, ma_uint64 initialSeekPoint, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream)
...@@ -64323,42 +64337,30 @@ static void* ma_resource_manager_data_stream_get_page_data_pointer(ma_resource_m ...@@ -64323,42 +64337,30 @@ static void* ma_resource_manager_data_stream_get_page_data_pointer(ma_resource_m
static void ma_resource_manager_data_stream_fill_page(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex) static void ma_resource_manager_data_stream_fill_page(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_bool32 isLooping;
ma_uint64 pageSizeInFrames; ma_uint64 pageSizeInFrames;
ma_uint64 totalFramesReadForThisPage = 0; ma_uint64 totalFramesReadForThisPage = 0;
void* pPageData = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pageIndex, 0); void* pPageData = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pageIndex, 0);
pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream);
isLooping = ma_resource_manager_data_stream_is_looping(pDataStream); /* Won't fail. */ /* The decoder needs to inherit the stream's looping and range state. */
{
if (isLooping) { ma_uint64 rangeBeg;
while (totalFramesReadForThisPage < pageSizeInFrames) { ma_uint64 rangeEnd;
ma_uint64 framesRemaining; ma_uint64 loopPointBeg;
ma_uint64 framesRead; ma_uint64 loopPointEnd;
framesRemaining = pageSizeInFrames - totalFramesReadForThisPage;
result = ma_decoder_read_pcm_frames(&pDataStream->decoder, ma_offset_pcm_frames_ptr(pPageData, totalFramesReadForThisPage, pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels), framesRemaining, &framesRead);
totalFramesReadForThisPage += framesRead;
/* Loop back to the start if we reached the end. We'll also have a known length at this point as well. */ ma_data_source_set_looping(&pDataStream->decoder, ma_resource_manager_data_stream_is_looping(pDataStream));
if (result == MA_AT_END || framesRead < framesRemaining) {
if (pDataStream->totalLengthInPCMFrames == 0) {
ma_decoder_get_cursor_in_pcm_frames(&pDataStream->decoder, &pDataStream->totalLengthInPCMFrames);
}
ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, 0); ma_data_source_get_range_in_pcm_frames(pDataStream, &rangeBeg, &rangeEnd);
result = MA_SUCCESS; /* Clear the AT_END result so we don't incorrectly mark this looping stream as at the end and then have it stopped. */ ma_data_source_set_range_in_pcm_frames(&pDataStream->decoder, rangeBeg, rangeEnd);
}
if (result != MA_SUCCESS && result != MA_AT_END) { ma_data_source_get_loop_point_in_pcm_frames(pDataStream, &loopPointBeg, &loopPointEnd);
break; ma_data_source_set_loop_point_in_pcm_frames(&pDataStream->decoder, loopPointBeg, loopPointEnd);
}
}
} else {
result = ma_decoder_read_pcm_frames(&pDataStream->decoder, pPageData, pageSizeInFrames, &totalFramesReadForThisPage);
} }
/* Just read straight from the decoder. It will deal with ranges and looping for us. */
result = ma_data_source_read_pcm_frames(&pDataStream->decoder, pPageData, pageSizeInFrames, &totalFramesReadForThisPage);
if (result == MA_AT_END || totalFramesReadForThisPage < pageSizeInFrames) { if (result == MA_AT_END || totalFramesReadForThisPage < pageSizeInFrames) {
c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_TRUE); c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_TRUE);
} }
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