diff --git a/examples/custom_backend.c b/examples/custom_backend.c index 504c967e..0e7577c2 100644 --- a/examples/custom_backend.c +++ b/examples/custom_backend.c @@ -417,7 +417,7 @@ static ma_result ma_device_init_internal__sdl(ma_device_ex* pDeviceEx, const ma_ pDescriptor->format = ma_format_from_sdl(obtainedSpec.format); pDescriptor->channels = obtainedSpec.channels; pDescriptor->sampleRate = (ma_uint32)obtainedSpec.freq; - ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); + ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); pDescriptor->periodSizeInFrames = obtainedSpec.samples; pDescriptor->periodCount = 1; /* SDL doesn't use the notion of period counts, so just set to 1. */ diff --git a/examples/data_source_chaining.c b/examples/data_source_chaining.c index 7bbd5c58..6d019903 100644 --- a/examples/data_source_chaining.c +++ b/examples/data_source_chaining.c @@ -65,7 +65,7 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, if you want to loop the chain, like we're doing in this example, you need to set the `loop` parameter to false, or else only the current data source will be looped. */ - ma_data_source_read_pcm_frames(&g_pDecoders[0], pOutput, frameCount, NULL, MA_FALSE); + ma_data_source_read_pcm_frames(&g_pDecoders[0], pOutput, frameCount, NULL); /* Unused in this example. */ (void)pDevice; diff --git a/examples/duplex_effect.c b/examples/duplex_effect.c index b0f1d522..933d24fd 100644 --- a/examples/duplex_effect.c +++ b/examples/duplex_effect.c @@ -100,7 +100,7 @@ int main(int argc, char** argv) goto done3; } - sourceNodeConfig = ma_data_source_node_config_init(&g_sourceData, MA_FALSE); + sourceNodeConfig = ma_data_source_node_config_init(&g_sourceData); result = ma_data_source_node_init(&g_nodeGraph, &sourceNodeConfig, NULL, &g_sourceNode); if (result != MA_SUCCESS) { @@ -118,7 +118,7 @@ int main(int argc, char** argv) goto done2; } - exciteNodeConfig = ma_data_source_node_config_init(&g_exciteData, MA_FALSE); + exciteNodeConfig = ma_data_source_node_config_init(&g_exciteData); result = ma_data_source_node_init(&g_nodeGraph, &exciteNodeConfig, NULL, &g_exciteNode); if (result != MA_SUCCESS) { diff --git a/examples/resource_manager.c b/examples/resource_manager.c index 55a1f939..0f9fabac 100644 --- a/examples/resource_manager.c +++ b/examples/resource_manager.c @@ -46,7 +46,7 @@ void main_loop__em(void* pUserData) void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - ma_data_source_read_pcm_frames((ma_data_source*)pDevice->pUserData, pOutput, frameCount, NULL, MA_TRUE); + ma_data_source_read_pcm_frames((ma_data_source*)pDevice->pUserData, pOutput, frameCount, NULL); (void)pInput; } @@ -108,6 +108,7 @@ int main(int argc, char** argv) &resourceManager, argv[1], MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM, + 0, /* Initial seek point. */ NULL, /* Async notification. */ &dataSource); if (result != MA_SUCCESS) { @@ -115,6 +116,9 @@ int main(int argc, char** argv) return -1; } + /* In this example we'll enable looping. */ + ma_data_source_set_looping(&dataSource, MA_TRUE); + /* Now that we have a sound we can start the device. */ result = ma_device_start(&device); diff --git a/examples/resource_manager_advanced.c b/examples/resource_manager_advanced.c index a5fbdd0c..20548938 100644 --- a/examples/resource_manager_advanced.c +++ b/examples/resource_manager_advanced.c @@ -27,7 +27,7 @@ static ma_uint32 g_dataSourceCount; TODO: Consider putting these public functions in miniaudio.h. Will depend on ma_mix_pcm_frames_f32() being merged into miniaudio.h (it's currently in miniaudio_engine.h). */ -static ma_result ma_data_source_read_pcm_frames_f32_ex(ma_data_source* pDataSource, float* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop, ma_format dataSourceFormat, ma_uint32 dataSourceChannels) +static ma_result ma_data_source_read_pcm_frames_f32_ex(ma_data_source* pDataSource, float* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_format dataSourceFormat, ma_uint32 dataSourceChannels) { /* This function is intended to be used when the format and channel count of the data source is @@ -37,7 +37,7 @@ static ma_result ma_data_source_read_pcm_frames_f32_ex(ma_data_source* pDataSour if (dataSourceFormat == ma_format_f32) { /* Fast path. No conversion necessary. */ - return ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, pFramesRead, loop); + return ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, pFramesRead); } else { /* Slow path. Conversion necessary. */ ma_result result; @@ -53,7 +53,7 @@ static ma_result ma_data_source_read_pcm_frames_f32_ex(ma_data_source* pDataSour framesToRead = tempCapInFrames; } - result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, framesToRead, &framesJustRead, loop); + result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, framesToRead, &framesJustRead); ma_convert_pcm_frames_format(ma_offset_pcm_frames_ptr_f32(pFramesOut, totalFramesRead, dataSourceChannels), ma_format_f32, temp, dataSourceFormat, framesJustRead, dataSourceChannels, ma_dither_mode_none); totalFramesRead += framesJustRead; @@ -67,7 +67,7 @@ static ma_result ma_data_source_read_pcm_frames_f32_ex(ma_data_source* pDataSour } } -MA_API ma_result ma_data_source_read_pcm_frames_f32(ma_data_source* pDataSource, float* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop) +MA_API ma_result ma_data_source_read_pcm_frames_f32(ma_data_source* pDataSource, float* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { ma_result result; ma_format format; @@ -78,10 +78,10 @@ MA_API ma_result ma_data_source_read_pcm_frames_f32(ma_data_source* pDataSource, return result; /* Failed to retrieve the data format of the data source. */ } - return ma_data_source_read_pcm_frames_f32_ex(pDataSource, pFramesOut, frameCount, pFramesRead, loop, format, channels); + return ma_data_source_read_pcm_frames_f32_ex(pDataSource, pFramesOut, frameCount, pFramesRead, format, channels); } -MA_API ma_result ma_data_source_read_pcm_frames_and_mix_f32(ma_data_source* pDataSource, float* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop, float volume) +MA_API ma_result ma_data_source_read_pcm_frames_and_mix_f32(ma_data_source* pDataSource, float* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, float volume) { ma_result result; ma_format format; @@ -111,7 +111,7 @@ MA_API ma_result ma_data_source_read_pcm_frames_and_mix_f32(ma_data_source* pDat framesToRead = tempCapInFrames; } - result = ma_data_source_read_pcm_frames_f32_ex(pDataSource, temp, framesToRead, &framesJustRead, loop, format, channels); + result = ma_data_source_read_pcm_frames_f32_ex(pDataSource, temp, framesToRead, &framesJustRead, format, channels); ma_mix_pcm_frames_f32(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), temp, framesJustRead, channels, volume); totalFramesRead += framesJustRead; @@ -149,7 +149,7 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin /* For each sound, mix as much data as we can. */ for (iDataSource = 0; iDataSource < g_dataSourceCount; iDataSource += 1) { - ma_data_source_read_pcm_frames_and_mix_f32(&g_dataSources[iDataSource], (float*)pOutput, frameCount, NULL, MA_TRUE, /* volume = */1); + ma_data_source_read_pcm_frames_and_mix_f32(&g_dataSources[iDataSource], (float*)pOutput, frameCount, NULL, /* volume = */1); } } @@ -275,6 +275,7 @@ int main(int argc, char** argv) &resourceManager, argv[iFile+1], MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC /*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM*/, + 0, /* Initial seek point. */ NULL, /* Async notification. */ &g_dataSources[iFile]); @@ -282,6 +283,9 @@ int main(int argc, char** argv) break; } + /* Use looping in this example. */ + ma_data_source_set_looping(&g_dataSources[iFile], MA_TRUE); + g_dataSourceCount += 1; } diff --git a/examples/simple_looping.c b/examples/simple_looping.c index 0c24e5be..dcc5a2b5 100644 --- a/examples/simple_looping.c +++ b/examples/simple_looping.c @@ -12,18 +12,13 @@ decoder straight into `ma_data_source_read_pcm_frames()` and it will just work. void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - ma_bool32 isLooping = MA_TRUE; - ma_decoder* pDecoder = (ma_decoder*)pDevice->pUserData; if (pDecoder == NULL) { return; } - /* - A decoder is a data source which means you can seemlessly plug it into the ma_data_source API. We can therefore take advantage - of the "loop" parameter of ma_data_source_read_pcm_frames() to handle looping for us. - */ - ma_data_source_read_pcm_frames(pDecoder, pOutput, frameCount, NULL, isLooping); + /* Reading PCM frames will loop based on what we specified when called ma_data_source_set_looping(). */ + ma_data_source_read_pcm_frames(pDecoder, pOutput, frameCount, NULL); (void)pInput; } @@ -45,6 +40,12 @@ int main(int argc, char** argv) return -2; } + /* + A decoder is a data source which means we just use ma_data_source_set_looping() to set the + looping state. We will read data using ma_data_source_read_pcm_frames() in the data callback. + */ + ma_data_source_set_looping(&decoder, MA_TRUE); + deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig.playback.format = decoder.outputFormat; deviceConfig.playback.channels = decoder.outputChannels; diff --git a/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c b/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c index aec9028b..7ebf23a1 100644 --- a/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c +++ b/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c @@ -115,7 +115,7 @@ int main(int argc, char** argv) /* Data supply. Attached to input bus 0 of the reverb node. */ - dataSupplyNodeConfig = ma_data_source_node_config_init(&g_decoder, MA_FALSE); + dataSupplyNodeConfig = ma_data_source_node_config_init(&g_decoder); result = ma_data_source_node_init(&g_nodeGraph, &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); if (result != MA_SUCCESS) { diff --git a/extras/nodes/ma_delay_node/ma_delay_node_example.c b/extras/nodes/ma_delay_node/ma_delay_node_example.c index 41063362..da8d4be0 100644 --- a/extras/nodes/ma_delay_node/ma_delay_node_example.c +++ b/extras/nodes/ma_delay_node/ma_delay_node_example.c @@ -84,7 +84,7 @@ int main(int argc, char** argv) goto done2; } - dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSupply, MA_FALSE); + dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSupply); result = ma_data_source_node_init(&g_nodeGraph, &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); if (result != MA_SUCCESS) { diff --git a/extras/nodes/ma_reverb_node/ma_reverb_node_example.c b/extras/nodes/ma_reverb_node/ma_reverb_node_example.c index 04bfdb80..d4fe8c00 100644 --- a/extras/nodes/ma_reverb_node/ma_reverb_node_example.c +++ b/extras/nodes/ma_reverb_node/ma_reverb_node_example.c @@ -85,7 +85,7 @@ int main(int argc, char** argv) goto done2; } - dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSupply, MA_FALSE); + dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSupply); result = ma_data_source_node_init(&g_nodeGraph, &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); if (result != MA_SUCCESS) { diff --git a/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c b/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c index 0daf1f0a..64170b13 100644 --- a/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c +++ b/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c @@ -100,7 +100,7 @@ int main(int argc, char** argv) goto done3; } - sourceNodeConfig = ma_data_source_node_config_init(&g_sourceData, MA_FALSE); + sourceNodeConfig = ma_data_source_node_config_init(&g_sourceData); result = ma_data_source_node_init(&g_nodeGraph, &sourceNodeConfig, NULL, &g_sourceNode); if (result != MA_SUCCESS) { @@ -118,7 +118,7 @@ int main(int argc, char** argv) goto done2; } - exciteNodeConfig = ma_data_source_node_config_init(&g_exciteData, MA_FALSE); + exciteNodeConfig = ma_data_source_node_config_init(&g_exciteData); result = ma_data_source_node_init(&g_nodeGraph, &exciteNodeConfig, NULL, &g_exciteNode); if (result != MA_SUCCESS) { diff --git a/miniaudio.h b/miniaudio.h index 95aa7aa8..7ba80064 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8287,17 +8287,19 @@ typedef struct ma_data_source* pCurrent; /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */ ma_data_source* pNext; /* When set to NULL, onGetNext will be used. */ ma_data_source_get_next_proc onGetNext; /* Will be used when pNext is NULL. If both are NULL, no next will be used. */ + MA_ATOMIC ma_bool32 isLooping; } ma_data_source_base; MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource); MA_API void ma_data_source_uninit(ma_data_source* pDataSource); -MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ -MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead, loop); */ +MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ +MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */ 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_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor); MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping); +MA_API ma_bool32 ma_data_source_is_looping(ma_data_source* pDataSource); MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames); MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames); MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames); @@ -9199,7 +9201,7 @@ MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_res MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength); MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer); MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping); -MA_API ma_result ma_resource_manager_data_buffer_get_looping(const ma_resource_manager_data_buffer* pDataBuffer, ma_bool32* pIsLooping); +MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer); MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames); /* Data Streams. */ @@ -9213,7 +9215,7 @@ MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_res MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength); MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream); MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping); -MA_API ma_result ma_resource_manager_data_stream_get_looping(const ma_resource_manager_data_stream* pDataStream, ma_bool32* pIsLooping); +MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream); MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames); /* Data Sources. */ @@ -9228,7 +9230,7 @@ MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_res MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength); MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource); MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping); -MA_API ma_result ma_resource_manager_data_source_get_looping(const ma_resource_manager_data_source* pDataSource, ma_bool32* pIsLooping); +MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource); MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames); /* Job management. */ @@ -9464,22 +9466,20 @@ typedef struct { ma_node_config nodeConfig; ma_data_source* pDataSource; - ma_bool32 looping; /* Can be changed after initialization with ma_data_source_node_set_looping(). */ } ma_data_source_node_config; -MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource, ma_bool32 looping); +MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource); typedef struct { ma_node_base base; ma_data_source* pDataSource; - MA_ATOMIC ma_bool32 looping; /* This can be modified and read across different threads. Must be used atomically. */ } ma_data_source_node; MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode); MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks); -MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 looping); +MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping); MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode); @@ -9808,7 +9808,6 @@ struct ma_sound ma_engine_node engineNode; /* Must be the first member for compatibility with the ma_node API. */ ma_data_source* pDataSource; ma_uint64 seekTarget; /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */ - MA_ATOMIC ma_bool32 isLooping; /* False by default. */ MA_ATOMIC ma_bool32 atEnd; ma_bool8 ownsDataSource; @@ -52227,11 +52226,12 @@ static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_ return MA_SUCCESS; } -static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop) +static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_result result; ma_uint64 framesRead = 0; + ma_bool32 loop = ma_data_source_is_looping(pDataSource); if (pDataSourceBase == NULL) { return MA_AT_END; @@ -52285,7 +52285,7 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa return result; } -MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop) +MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { ma_result result = MA_SUCCESS; ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; @@ -52295,6 +52295,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi ma_format format; ma_uint32 channels; ma_uint32 emptyLoopCounter = 0; /* Keeps track of how many times 0 frames have been read. For infinite loop detection of sounds with no audio data. */ + ma_bool32 loop; if (pFramesRead != NULL) { *pFramesRead = 0; @@ -52308,6 +52309,8 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi return MA_INVALID_ARGS; } + loop = ma_data_source_is_looping(pDataSource); + /* We need to know the data format so we can advance the output buffer as we read frames. If this fails, chaining will not work and we'll just read as much as we can from the current source. @@ -52318,7 +52321,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi return result; } - return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead, loop); + return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead); } /* @@ -52341,7 +52344,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi break; } - result = ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pRunningFramesOut, framesRemaining, &framesProcessed, loop); + result = ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pRunningFramesOut, framesRemaining, &framesProcessed); totalFramesProcessed += framesProcessed; /* @@ -52423,9 +52426,9 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi return result; } -MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop) +MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked) { - return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked, loop); + return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked); } MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex) @@ -52575,6 +52578,8 @@ MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool return MA_INVALID_ARGS; } + c89atomic_exchange_32(&pDataSourceBase->isLooping, isLooping); + /* If there's no callback for this just treat it as a successful no-op. */ if (pDataSourceBase->vtable->onSetLooping == NULL) { return MA_SUCCESS; @@ -52583,6 +52588,17 @@ MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool return pDataSourceBase->vtable->onSetLooping(pDataSource, isLooping); } +MA_API ma_bool32 ma_data_source_is_looping(ma_data_source* pDataSource) +{ + ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + + if (pDataSource == NULL) { + return MA_FALSE; + } + + return c89atomic_load_32(&pDataSourceBase->isLooping); +} + MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames) { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; @@ -59657,14 +59673,14 @@ MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO /* Fast path. */ if (pDecoder->converter.isPassthrough) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pFramesOut, frameCount, &totalFramesReadOut, MA_FALSE); + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pFramesOut, frameCount, &totalFramesReadOut); } else { /* Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we need to run through each sample because we need to ensure it's internal cache is updated. */ if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut, MA_FALSE); + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut); } else { /* Slow path. Need to run everything through the data converter. */ ma_format internalFormat; @@ -59721,7 +59737,7 @@ MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO if (pDecoder->inputCacheRemaining == 0) { pDecoder->inputCacheConsumed = 0; - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pDecoder->pInputCache, pDecoder->inputCacheCap, &pDecoder->inputCacheRemaining, MA_FALSE); + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pDecoder->pInputCache, pDecoder->inputCacheCap, &pDecoder->inputCacheRemaining); if (result != MA_SUCCESS) { break; } @@ -59750,7 +59766,7 @@ MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO } if (requiredInputFrameCount > 0) { - result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn, MA_FALSE); + result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn); } else { framesReadThisIterationIn = 0; } @@ -62676,6 +62692,23 @@ static ma_result ma_resource_manager__init_decoder(ma_resource_manager* pResourc return MA_SUCCESS; } +static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource_manager_data_buffer* pDataBuffer) +{ + switch (pDataBuffer->pNode->data.type) + { + case ma_resource_manager_data_supply_type_encoded: return &pDataBuffer->connector.decoder; + case ma_resource_manager_data_supply_type_decoded: return &pDataBuffer->connector.buffer; + case ma_resource_manager_data_supply_type_decoded_paged: return &pDataBuffer->connector.pagedBuffer; + + case ma_resource_manager_data_supply_type_unknown: + default: + { + ma_log_postf(ma_resource_manager_get_log(pDataBuffer->pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to retrieve data buffer connector. Unknown data supply type.\n"); + return NULL; + }; + }; +} + static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_manager_data_buffer* pDataBuffer, ma_async_notification* pInitNotification, ma_fence* pInitFence) { ma_result result; @@ -62730,6 +62763,12 @@ static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_mana the format/channels/rate of the data source. */ if (result == MA_SUCCESS) { + /* + Make sure the looping state is set before returning in order to handle the case where the + loop state was set on the data buffer before the connector was initialized. + */ + ma_data_source_set_looping(ma_resource_manager_data_buffer_get_connector(pDataBuffer), ma_resource_manager_data_buffer_is_looping(pDataBuffer)); + pDataBuffer->isConnectorInitialized = MA_TRUE; if (pInitNotification != NULL) { @@ -62784,23 +62823,6 @@ static ma_uint32 ma_resource_manager_data_buffer_node_next_execution_order(ma_re return c89atomic_fetch_add_32(&pDataBufferNode->executionCounter, 1); } -static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource_manager_data_buffer* pDataBuffer) -{ - switch (pDataBuffer->pNode->data.type) - { - case ma_resource_manager_data_supply_type_encoded: return &pDataBuffer->connector.decoder; - case ma_resource_manager_data_supply_type_decoded: return &pDataBuffer->connector.buffer; - case ma_resource_manager_data_supply_type_decoded_paged: return &pDataBuffer->connector.pagedBuffer; - - case ma_resource_manager_data_supply_type_unknown: - default: - { - ma_log_postf(ma_resource_manager_get_log(pDataBuffer->pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to retrieve data buffer connector. Unknown data supply type.\n"); - return NULL; - }; - }; -} - static ma_result ma_resource_manager_data_buffer_node_init_supply_encoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW) { ma_result result; @@ -63429,6 +63451,11 @@ static ma_result ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames(ma return ma_resource_manager_data_buffer_get_length_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pLength); } +static ma_result ma_resource_manager_data_buffer_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) +{ + return ma_resource_manager_data_buffer_set_looping((ma_resource_manager_data_buffer*)pDataSource, isLooping); +} + static ma_data_source_vtable g_ma_resource_manager_data_buffer_vtable = { ma_resource_manager_data_buffer_cb__read_pcm_frames, @@ -63436,7 +63463,7 @@ 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_cursor_in_pcm_frames, ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames, - NULL /* onSetLooping */ + ma_resource_manager_data_buffer_cb__set_looping }; 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) @@ -63677,7 +63704,6 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man { ma_result result = MA_SUCCESS; ma_uint64 framesRead = 0; - ma_bool32 isLooping; ma_bool32 isDecodedBufferBusy = MA_FALSE; /* Safety. */ @@ -63709,11 +63735,6 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man } } - result = ma_resource_manager_data_buffer_get_looping(pDataBuffer, &isLooping); - if (result != MA_SUCCESS) { - return result; - } - /* For decoded buffers (not paged) we need to check beforehand how many frames we have available. We cannot exceed this amount. We'll read as much as we can, and then return MA_BUSY. @@ -63746,7 +63767,7 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man /* Don't attempt to read anything if we've got no frames available. */ if (frameCount > 0) { - result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead, isLooping); + result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead); } /* @@ -63915,24 +63936,19 @@ MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager c89atomic_exchange_32(&pDataBuffer->isLooping, isLooping); + /* The looping state needs to be set on the connector as well or else looping won't work when we read audio data. */ + ma_data_source_set_looping(ma_resource_manager_data_buffer_get_connector(pDataBuffer), isLooping); + return MA_SUCCESS; } -MA_API ma_result ma_resource_manager_data_buffer_get_looping(const ma_resource_manager_data_buffer* pDataBuffer, ma_bool32* pIsLooping) +MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer) { - if (pIsLooping == NULL) { - return MA_INVALID_ARGS; - } - - *pIsLooping = MA_FALSE; - if (pDataBuffer == NULL) { - return MA_INVALID_ARGS; + return MA_FALSE; } - *pIsLooping = c89atomic_load_32((ma_bool32*)&pDataBuffer->isLooping); - - return MA_SUCCESS; + return c89atomic_load_32((ma_bool32*)&pDataBuffer->isLooping); } MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames) @@ -64305,7 +64321,7 @@ static void ma_resource_manager_data_stream_fill_page(ma_resource_manager_data_s pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); - ma_resource_manager_data_stream_get_looping(pDataStream, &isLooping); /* Won't fail. */ + isLooping = ma_resource_manager_data_stream_is_looping(pDataStream); /* Won't fail. */ if (isLooping) { while (totalFramesReadForThisPage < pageSizeInFrames) { @@ -64716,21 +64732,13 @@ MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager return MA_SUCCESS; } -MA_API ma_result ma_resource_manager_data_stream_get_looping(const ma_resource_manager_data_stream* pDataStream, ma_bool32* pIsLooping) +MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream) { - if (pIsLooping == NULL) { - return MA_INVALID_ARGS; - } - - *pIsLooping = MA_FALSE; - if (pDataStream == NULL) { - return MA_INVALID_ARGS; + return MA_FALSE; } - *pIsLooping = c89atomic_load_32((ma_bool32*)&pDataStream->isLooping); /* Naughty const-cast. Value won't change from here in practice (maybe from another thread). */ - - return MA_SUCCESS; + return c89atomic_load_32((ma_bool32*)&pDataStream->isLooping); /* Naughty const-cast. Value won't change from here in practice (maybe from another thread). */ } MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames) @@ -64975,16 +64983,16 @@ MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager } } -MA_API ma_result ma_resource_manager_data_source_get_looping(const ma_resource_manager_data_source* pDataSource, ma_bool32* pIsLooping) +MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource) { - if (pDataSource == NULL || pIsLooping == NULL) { - return MA_INVALID_ARGS; + if (pDataSource == NULL) { + return MA_FALSE; } if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) { - return ma_resource_manager_data_stream_get_looping(&pDataSource->backend.stream, pIsLooping); + return ma_resource_manager_data_stream_is_looping(&pDataSource->backend.stream); } else { - return ma_resource_manager_data_buffer_get_looping(&pDataSource->backend.buffer, pIsLooping); + return ma_resource_manager_data_buffer_is_looping(&pDataSource->backend.buffer); } } @@ -67397,14 +67405,13 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde /* Data source node. */ -MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource, ma_bool32 looping) +MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource) { ma_data_source_node_config config; MA_ZERO_OBJECT(&config); config.nodeConfig = ma_node_config_init(); config.pDataSource = pDataSource; - config.looping = looping; return config; } @@ -67437,7 +67444,7 @@ static void ma_data_source_node_process_pcm_frames(ma_node* pNode, const float** MA_ASSERT(format == ma_format_f32); (void)format; /* Just to silence some static analysis tools. */ - ma_data_source_read_pcm_frames(pDataSourceNode->pDataSource, ppFramesOut[0], frameCount, &framesRead, c89atomic_load_32(&pDataSourceNode->looping)); + ma_data_source_read_pcm_frames(pDataSourceNode->pDataSource, ppFramesOut[0], frameCount, &framesRead); } *pFrameCountOut = (ma_uint32)framesRead; @@ -67502,7 +67509,6 @@ MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_da } pDataSourceNode->pDataSource = pConfig->pDataSource; - pDataSourceNode->looping = pConfig->looping; return MA_SUCCESS; } @@ -67512,15 +67518,13 @@ MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, con ma_node_uninit(&pDataSourceNode->base, pAllocationCallbacks); } -MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 looping) +MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping) { if (pDataSourceNode == NULL) { return MA_INVALID_ARGS; } - c89atomic_exchange_32(&pDataSourceNode->looping, looping); - - return MA_SUCCESS; + return ma_data_source_set_looping(pDataSourceNode->pDataSource, isLooping); } MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode) @@ -67529,7 +67533,7 @@ MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSource return MA_FALSE; } - return c89atomic_load_32(&pDataSourceNode->looping); + return ma_data_source_is_looping(pDataSourceNode->pDataSource); } @@ -68804,7 +68808,7 @@ static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float framesToRead = tempCapInFrames; } - result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToRead, &framesJustRead, ma_sound_is_looping(pSound)); + result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToRead, &framesJustRead); /* If we reached the end of the sound we'll want to mark it as at the end and stop it. This should never be returned for looping sounds. */ if (result == MA_AT_END) { @@ -70713,12 +70717,7 @@ MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping) return; } - c89atomic_exchange_32(&pSound->isLooping, isLooping); - - /* - Some data sources, in particular resource managed streams, need to know about the looping state - so they can do clean loop transitions. - */ + /* The looping state needs to be applied to the data source in order for any looping to actually happen. */ ma_data_source_set_looping(pSound->pDataSource, isLooping); } @@ -70733,7 +70732,7 @@ MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound) return MA_FALSE; } - return c89atomic_load_32(&pSound->isLooping); + return ma_data_source_is_looping(pSound->pDataSource); } MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound) @@ -87476,6 +87475,9 @@ Breaking API Changes -------------------- There are many breaking API changes in this release. + - The "loop" parameter has been removed from ma_data_source_read_pcm_frames(). To enabled looping + you now need to call ma_data_source_set_looping(). The looping state can be retrieved with + ma_data_source_is_looping(). - ma_channel_mix_mode_planar_blend has been removed. Use ma_channel_mix_mode_rectangular instead. - MA_MIN_SAMPLE_RATE and MA_MAX_SAMPLE_RATE have been removed. Use ma_standard_sample_rate_min and ma_standard_sample_rate_max instead.