mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Fix a bug relating to the handling of looping sounds.
This commit is contained in:
+61
-41
@@ -1367,7 +1367,7 @@ struct ma_resource_manager_data_buffer
|
||||
ma_uint32 flags; /* The flags that were passed used to initialize the buffer. */
|
||||
ma_uint32 executionCounter; /* For allocating execution orders for jobs. */
|
||||
ma_uint32 executionPointer; /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
|
||||
ma_uint64 cursorInPCMFrames; /* Only updated by the public API. Never written nor read from the job thread. */
|
||||
ma_uint64 seekTargetInPCMFrames; /* Only updated by the public API. Never written nor read from the job thread. */
|
||||
ma_bool32 seekToCursorOnNextRead; /* On the next read we need to seek to the frame cursor. */
|
||||
MA_ATOMIC ma_result result; /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */
|
||||
MA_ATOMIC ma_bool32 isLooping; /* Can be read and written by different threads at the same time. Must be used atomically. */
|
||||
@@ -7445,7 +7445,7 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man
|
||||
if (pDataBuffer->seekToCursorOnNextRead) {
|
||||
pDataBuffer->seekToCursorOnNextRead = MA_FALSE;
|
||||
|
||||
result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pDataBuffer->cursorInPCMFrames);
|
||||
result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pDataBuffer->seekTargetInPCMFrames);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
@@ -7457,45 +7457,42 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man
|
||||
*/
|
||||
if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_decoded) {
|
||||
ma_uint64 availableFrames;
|
||||
|
||||
isDecodedBufferBusy = (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY);
|
||||
|
||||
if (ma_resource_manager_data_buffer_get_available_frames(pDataBuffer, &availableFrames) == MA_SUCCESS) {
|
||||
/* Don't try reading more than the available frame count. */
|
||||
if (frameCount > availableFrames) {
|
||||
frameCount = availableFrames;
|
||||
isDecodedBufferBusy = (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY);
|
||||
|
||||
if (!isDecodedBufferBusy && availableFrames == 0) {
|
||||
result = MA_AT_END;
|
||||
}
|
||||
} else {
|
||||
isDecodedBufferBusy = MA_FALSE; /* We have enough frames available in the buffer to avoid a MA_BUSY status. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == MA_SUCCESS) {
|
||||
result = ma_resource_manager_data_buffer_get_looping(pDataBuffer, &isLooping);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
result = ma_resource_manager_data_buffer_get_looping(pDataBuffer, &isLooping);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead, isLooping);
|
||||
pDataBuffer->cursorInPCMFrames += framesRead;
|
||||
result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead, isLooping);
|
||||
|
||||
/*
|
||||
If we returned MA_AT_END, but the node is still loading, we don't want to return that code or else the caller will interpret the sound
|
||||
as at the end and terminate decoding.
|
||||
*/
|
||||
if (result == MA_AT_END) {
|
||||
if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) {
|
||||
result = MA_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDecodedBufferBusy) {
|
||||
/*
|
||||
If we returned MA_AT_END, but the node is still loading, we don't want to return that code or else the caller will interpret the sound
|
||||
as at the end and terminate decoding.
|
||||
*/
|
||||
if (result == MA_AT_END) {
|
||||
if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) {
|
||||
result = MA_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = framesRead;
|
||||
}
|
||||
if (isDecodedBufferBusy) {
|
||||
result = MA_BUSY;
|
||||
}
|
||||
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = framesRead;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -7510,7 +7507,7 @@ MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_m
|
||||
|
||||
/* If we haven't yet got a connector we need to abort. */
|
||||
if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) {
|
||||
pDataBuffer->cursorInPCMFrames = frameIndex;
|
||||
pDataBuffer->seekTargetInPCMFrames = frameIndex;
|
||||
pDataBuffer->seekToCursorOnNextRead = MA_TRUE;
|
||||
return MA_BUSY; /* Still loading. */
|
||||
}
|
||||
@@ -7520,7 +7517,7 @@ MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_m
|
||||
return result;
|
||||
}
|
||||
|
||||
pDataBuffer->cursorInPCMFrames = frameIndex;
|
||||
pDataBuffer->seekTargetInPCMFrames = ~(ma_uint64)0; /* <-- For identification purposes. */
|
||||
pDataBuffer->seekToCursorOnNextRead = MA_FALSE;
|
||||
|
||||
return MA_SUCCESS;
|
||||
@@ -7576,9 +7573,35 @@ MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_res
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pCursor = pDataBuffer->cursorInPCMFrames;
|
||||
*pCursor = 0;
|
||||
|
||||
return MA_SUCCESS;
|
||||
switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode))
|
||||
{
|
||||
case ma_resource_manager_data_supply_type_encoded:
|
||||
{
|
||||
return ma_decoder_get_cursor_in_pcm_frames(&pDataBuffer->connector.decoder, pCursor);
|
||||
};
|
||||
|
||||
case ma_resource_manager_data_supply_type_decoded:
|
||||
{
|
||||
return ma_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.buffer, pCursor);
|
||||
};
|
||||
|
||||
case ma_resource_manager_data_supply_type_decoded_paged:
|
||||
{
|
||||
return ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, pCursor);
|
||||
};
|
||||
|
||||
case ma_resource_manager_data_supply_type_unknown:
|
||||
{
|
||||
return MA_BUSY;
|
||||
};
|
||||
|
||||
default:
|
||||
{
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength)
|
||||
@@ -7663,19 +7686,16 @@ MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resourc
|
||||
|
||||
case ma_resource_manager_data_supply_type_decoded:
|
||||
{
|
||||
if (pDataBuffer->pNode->data.decoded.decodedFrameCount > pDataBuffer->cursorInPCMFrames) {
|
||||
*pAvailableFrames = pDataBuffer->pNode->data.decoded.decodedFrameCount - pDataBuffer->cursorInPCMFrames;
|
||||
} else {
|
||||
*pAvailableFrames = 0;
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
return ma_audio_buffer_get_available_frames(&pDataBuffer->connector.buffer, pAvailableFrames);
|
||||
};
|
||||
|
||||
case ma_resource_manager_data_supply_type_decoded_paged:
|
||||
{
|
||||
if (pDataBuffer->pNode->data.decodedPaged.decodedFrameCount > pDataBuffer->cursorInPCMFrames) {
|
||||
*pAvailableFrames = pDataBuffer->pNode->data.decodedPaged.decodedFrameCount - pDataBuffer->cursorInPCMFrames;
|
||||
ma_uint64 cursor;
|
||||
ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, &cursor);
|
||||
|
||||
if (pDataBuffer->pNode->data.decodedPaged.decodedFrameCount > cursor) {
|
||||
*pAvailableFrames = pDataBuffer->pNode->data.decodedPaged.decodedFrameCount - cursor;
|
||||
} else {
|
||||
*pAvailableFrames = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user