@@ -87,7 +87,7 @@ useful to be told exactly what it being allocated so you can optimize your alloc
#define MA_ALLOCATION_TYPE_AUDIO_BUFFER 0x00000005 /* A ma_audio_buffer allocation. */
#define MA_ALLOCATION_TYPE_ENCODED_BUFFER 0x00000006 /* Allocation for encoded audio data containing the raw file data of a sound file. */
#define MA_ALLOCATION_TYPE_DECODED_BUFFER 0x00000007 /* Allocation for decoded audio data from a sound file. */
#define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_NODE 0x00000010 /* A ma_resource_manager_data_node object. */
#define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_NODE 0x00000010 /* A ma_resource_manager_data_buffer object. */
#define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_PAGE 0x00000011 /* A ma_resource_manager_page object. Used by the resource manager for when a page containing decoded audio data is loaded for streaming. */
#define MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_SOURCE 0x00000012 /* A ma_resource_manager_data_source object. */
...
...
@@ -104,9 +104,9 @@ The flags below are used for controlling how the resource manager should handle
char*pFilePath;/* Allocated when the message is posted, freed by the async thread after loading. */
ma_event*pEvent;
}loadDataNode;
}loadDataBuffer;
struct
{
ma_resource_manager_data_node*pDataNode;
}freeDataNode;
ma_resource_manager_data_buffer*pDataBuffer;
}freeDataBuffer;
struct
{
ma_resource_manager_data_source*pDataSource;
...
...
@@ -163,13 +163,13 @@ typedef struct
}freeDataSource;
struct
{
ma_resource_manager_data_node*pDataNode;
ma_resource_manager_data_buffer*pDataBuffer;
ma_decoder*pDecoder;
ma_event*pCompletedEvent;/* Signalled when the data buffer has been fully decoded. */
void*pData;
size_tdataSizeInBytes;
ma_uint64decodedFrameCount;
ma_bool32isUnknownLength;/* When set to true does not update the running frame count of the data node nor the data pointer until the last page has been decoded. */
ma_bool32isUnknownLength;/* When set to true does not update the running frame count of the data buffer nor the data pointer until the last page has been decoded. */
}decodePage;
};
}ma_resource_manager_message;
...
...
@@ -211,7 +211,7 @@ typedef struct
typedefstruct
{
ma_resource_manager_data_node_typetype;
ma_resource_manager_data_buffer_typetype;
union
{
ma_decoded_datadecoded;
...
...
@@ -219,22 +219,22 @@ typedef struct
};
}ma_resource_manager_memory_buffer;
structma_resource_manager_data_node
structma_resource_manager_data_buffer
{
ma_uint32hashedName32;/* The hashed name. This is the key. */
ma_uint32refCount;
ma_resultresult;/* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */
ma_bool32isDataOwnedByResourceManager;
ma_resource_manager_memory_bufferdata;
ma_resource_manager_data_node*pParent;
ma_resource_manager_data_node*pChildLo;
ma_resource_manager_data_node*pChildHi;
ma_resource_manager_data_buffer*pParent;
ma_resource_manager_data_buffer*pChildLo;
ma_resource_manager_data_buffer*pChildHi;
};
structma_resource_manager_data_source
{
ma_data_source_callbacksds;
ma_resource_manager_data_node*pDataNode;
ma_resource_manager_data_buffer*pDataBuffer;
ma_resource_manager_data_source_typetype;
ma_uint32flags;/* The flags that were passed in to ma_resource_manager_data_source_init(). */
ma_resultresult;/* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */
MA_APIma_resultma_resource_manager_register_decoded_data(ma_resource_manager*pResourceManager,constchar*pName,constvoid*pData,ma_uint64frameCount,ma_formatformat,ma_uint32channels,ma_uint32sampleRate);/* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
MA_APIma_resultma_resource_manager_register_encoded_data(ma_resource_manager*pResourceManager,constchar*pName,constvoid*pData,size_tsizeInBytes);/* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
/* We need to find the node that will become the parent of the new node. If a node is found that already has the same hashed name we need to return MA_ALREADY_EXISTS. */
/* For now we are just going to use the in-order successor as the replacement, but we may want to try to keep this balanced by switching between the two. */
Now that we have our replacement node we can make the change. The simple way to do this would be to just exchange the values, and then remove the replacement
...
...
@@ -1107,49 +1107,49 @@ static ma_result ma_resource_manager_data_node_remove(ma_resource_manager* pReso
replacement node should have at most 1 child. Therefore, we can detach it in terms of our simpler cases above. What we're essentially doing is detaching the
replacement node and reinserting it into the same position as the deleted node.
*/
MA_ASSERT(pReplacementDataNode->pParent!=NULL);/* The replacement node should never be the root which means it should always have a parent. */
MA_ASSERT(pReplacementDataNode->pChildLo==NULL);/* Because we used in-order successor. This would be pChildHi == NULL if we used in-order predecessor. */
MA_ASSERT(pReplacementDataBuffer->pParent!=NULL);/* The replacement node should never be the root which means it should always have a parent. */
MA_ASSERT(pReplacementDataBuffer->pChildLo==NULL);/* Because we used in-order successor. This would be pChildHi == NULL if we used in-order predecessor. */
/* The replacement node has essentially been detached from the binary tree, so now we need to replace the old data node with it. The first thing to update is the parent */
/* The replacement node has essentially been detached from the binary tree, so now we need to replace the old data buffer with it. The first thing to update is the parent */
char*pFilePathCopy;/* Allocated here, freed in the resource thread. */
MA_ASSERT(pResourceManager!=NULL);
MA_ASSERT(pFilePath!=NULL);
MA_ASSERT(ppDataNode!=NULL);
MA_ASSERT(ppDataBuffer!=NULL);
/*
The first thing to do is find the insertion point. If it's already loaded it means we can just increment the reference counter and signal the event. Otherwise we
/* Slow path. The data for this buffer has not yet been initialized. The first thing to do is allocate the new data buffer and insert it into the BST. */
/* We now have everything we need to post the message to the resource thread. This is the last thing we need to do from here. The rest will be done by the resource thread. */
/* If the reference count has hit zero it means we need to delete the data node and it's backing data (so long as it's owned by the resource manager). */
/* If the reference count has hit zero it means we need to delete the data buffer and it's backing data (so long as it's owned by the resource manager). */
It's assumed that the data specified by pName was registered with a prior call to ma_resource_manager_register_encoded/decoded_data(). To unregister it, all
we need to do is delete the node by it's name.
we need to do is delete the data buffer by it's name.
will abort with MA_BUSY. We could also choose to do a partial read (only reading as many frames are available), but it's just easier to abort early and I don't think it
really makes much practical difference. This only applies to decoded buffers.
an ma_audio_buffer if the data format is identical to the primary format. This enables us to use memory mapping when mixing which saves us a bit of data
configOut=ma_decoder_config_init(pResourceManager->config.decodedFormat,pDataNode->data.decoded.channels,pResourceManager->config.decodedSampleRate);/* <-- Never perform channel conversion at this level - that will be done at a higher level. */
configOut=ma_decoder_config_init(pResourceManager->config.decodedFormat,pDataBuffer->data.decoded.channels,pResourceManager->config.decodedSampleRate);/* <-- Never perform channel conversion at this level - that will be done at a higher level. */
result=ma_decoder_init_memory_raw(pDataNode->data.decoded.pData,(size_t)sizeInBytes,&configIn,&configOut,&pDataSource->backend.decoder);/* Safe cast thanks to the check above. */
result=ma_decoder_init_memory_raw(pDataBuffer->data.decoded.pData,(size_t)sizeInBytes,&configIn,&configOut,&pDataSource->backend.decoder);/* Safe cast thanks to the check above. */
pDataSource->type=ma_resource_manager_data_source_type_unknown;/* The backend type hasn't been determine yet - that happens when it's initialized properly by the resource thread. */
pDataSource->result=MA_BUSY;
/*
If the data node has been fully initialized we can complete initialization of the data source now. Otherwise we need to post an event to the resource thread to complete
initialization to ensure it's done after the data node.
If the data buffer has been fully initialized we can complete initialization of the data source now. Otherwise we need to post an event to the resource thread to complete
initialization to ensure it's done after the data buffer.
We can initialize the data source if there is a non-zero decoded frame count. If the sound is being loaded synchronously or there are no frames available we need to re-insert
/* When the length is unknown we were doubling the size of the buffer each time we needed more data. Let's try reducing this by doing a final realloc(). */