Commit 1897c599 authored by David Reid's avatar David Reid

Add support for initializing a sound from another.

This only works for non-streaming sounds whose data source was created
via the resource manager.
parent 236da866
......@@ -35,6 +35,7 @@ int main(int argc, char** argv)
ma_resource_manager_config resourceManagerConfig;
ma_engine engine;
ma_engine_config engineConfig;
ma_sound baseSound;
ma_sound sound;
ma_sound sound2;
sound_loaded_notification loadNotification;
......@@ -78,12 +79,19 @@ int main(int argc, char** argv)
loadNotification.cb.onSignal = on_sound_loaded;
loadNotification.pSound = &sound;
result = ma_sound_init_from_file(&engine, argv[1], MA_DATA_SOURCE_FLAG_DECODE /*| MA_DATA_SOURCE_FLAG_ASYNC | MA_DATA_SOURCE_FLAG_STREAM*/, &group, &sound);
result = ma_sound_init_from_file(&engine, argv[1], MA_DATA_SOURCE_FLAG_DECODE /*| MA_DATA_SOURCE_FLAG_ASYNC | MA_DATA_SOURCE_FLAG_STREAM*/, &group, &baseSound);
if (result != MA_SUCCESS) {
printf("Failed to load sound: %s\n", argv[1]);
ma_engine_uninit(&engine);
return -1;
}
result = ma_sound_init_copy(&engine, &baseSound, 0, &group, &sound);
if (result != MA_SUCCESS) {
printf("Failed to copy sound.\n");
return -1;
}
#if 0
result = ma_sound_init_from_file(&engine, argv[1], MA_DATA_SOURCE_FLAG_DECODE /*| MA_DATA_SOURCE_FLAG_ASYNC | MA_DATA_SOURCE_FLAG_STREAM*/, NULL, &sound2);
if (result != MA_SUCCESS) {
......
......@@ -1377,6 +1377,7 @@ MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pRes
/* Data Buffers. */
MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, ma_async_notification* pNotification, ma_resource_manager_data_buffer* pDataBuffer);
MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, ma_async_notification* pNotification, ma_resource_manager_data_buffer* pDataBuffer);
MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer);
MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer);
MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex);
......@@ -1409,6 +1410,7 @@ MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resourc
/* Data Sources. */
MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, ma_async_notification* pNotification, ma_resource_manager_data_source* pDataSource);
MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, ma_async_notification* pNotification, ma_resource_manager_data_source* pDataSource);
MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource);
MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource);
MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex);
......@@ -1810,6 +1812,7 @@ MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath,
#ifndef MA_NO_RESOURCE_MANAGER
MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound);
MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound);
MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound);
#endif
MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound);
MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound);
......@@ -6204,7 +6207,6 @@ static ma_result ma_resource_manager_data_buffer_init_nolock(ma_resource_manager
ma_bool32 async;
MA_ASSERT(pResourceManager != NULL);
MA_ASSERT(pFilePath != NULL || pFilePathW != NULL);
MA_ASSERT(pDataBuffer != NULL);
MA_ZERO_OBJECT(pDataBuffer);
......@@ -6272,7 +6274,20 @@ static ma_result ma_resource_manager_data_buffer_init_nolock(ma_resource_manager
ma_async_notification_signal(pNotification, MA_NOTIFICATION_COMPLETE);
}
} else {
/* 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. */
/*
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.
Note that there's a possiblity that we're calling this function because we're wanting to
initialize a data buffer from an existing data buffer rather than by a file name. In this
case the file path will be NULL. This means the caller has uninitialized the last reference
to the underlying node. This is an invalid usage - the caller must ensure the existing data
buffer stays valid while cloning.
*/
if (pFilePath == NULL && pFilePathW == NULL) {
return MA_INVALID_OPERATION;
}
pDataBuffer->pNode = (ma_resource_manager_data_buffer_node*)ma__malloc_from_callbacks(sizeof(*pDataBuffer->pNode), &pResourceManager->config.allocationCallbacks/*, MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_BUFFER*/);
if (pDataBuffer->pNode == NULL) {
return MA_OUT_OF_MEMORY;
......@@ -6286,6 +6301,7 @@ static ma_result ma_resource_manager_data_buffer_init_nolock(ma_resource_manager
result = ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBuffer->pNode, pInsertPoint);
if (result != MA_SUCCESS) {
ma__free_from_callbacks(pDataBuffer->pNode, &pResourceManager->config.allocationCallbacks/*, MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_BUFFER*/);
return result; /* Should never happen. Failed to insert the data buffer into the BST. */
}
......@@ -6542,6 +6558,31 @@ MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pRe
return ma_resource_manager_data_buffer_init_internal(pResourceManager, NULL, pFilePath, flags, pNotification, pDataBuffer);
}
MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer)
{
ma_result result = MA_SUCCESS;
if (pDataBuffer == NULL) {
return MA_INVALID_ARGS;
}
if (pResourceManager == NULL || pExistingDataBuffer == NULL) {
return MA_INVALID_ARGS;
}
/*
We need to enter a critical section to ensure the existing data buffer doesn't get uninitialized while we're in the middle of
incrementing the reference count.
*/
ma_resource_manager_data_buffer_bst_lock(pResourceManager);
{
result = ma_resource_manager_data_buffer_init_nolock(pResourceManager, NULL, NULL, pExistingDataBuffer->pNode->hashedName32, pExistingDataBuffer->flags, NULL, pDataBuffer); /* Flags won't actually be used, but want them to be maintained for copied data buffers. */
}
ma_resource_manager_data_buffer_bst_unlock(pResourceManager);
return result;
}
static ma_result ma_resource_manager_data_buffer_uninit_internal(ma_resource_manager_data_buffer* pDataBuffer)
{
MA_ASSERT(pDataBuffer != NULL);
......@@ -7772,6 +7813,27 @@ MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pRe
}
}
MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource)
{
ma_result result;
if (pExistingDataSource == NULL) {
return MA_INVALID_ARGS;
}
result = ma_resource_manager_data_source_preinit(pResourceManager, pExistingDataSource->flags, pDataSource);
if (result != MA_SUCCESS) {
return result;
}
/* Copying can only be done from data buffers. Streams cannot be copied. */
if ((pExistingDataSource->flags & MA_DATA_SOURCE_FLAG_STREAM) != 0) {
return MA_INVALID_OPERATION;
}
return ma_resource_manager_data_buffer_init_copy(pResourceManager, &pExistingDataSource->buffer, &pDataSource->buffer);
}
MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource)
{
if (pDataSource == NULL) {
......@@ -11413,6 +11475,51 @@ MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pF
config.pInitialAttachment = pGroup;
return ma_sound_init_ex(pEngine, &config, pSound);
}
MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound)
{
ma_result result;
ma_sound_config config;
if (pEngine == NULL || pExistingSound == NULL) {
return MA_INVALID_ARGS;
}
/* Cloning only works for data buffers (not streams) that are loaded from the resource manager. */
if (pExistingSound->pResourceManagerDataSource == NULL) {
return MA_INVALID_OPERATION;
}
/*
We need to make a clone of the data source. If the data source is not a data buffer (i.e. a stream)
the this will fail.
*/
pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks);
if (pSound->pResourceManagerDataSource == NULL) {
return MA_OUT_OF_MEMORY;
}
result = ma_resource_manager_data_source_init_copy(pEngine->pResourceManager, pExistingSound->pResourceManagerDataSource, pSound->pResourceManagerDataSource);
if (result != MA_SUCCESS) {
ma_free(pSound, &pEngine->allocationCallbacks);
return result;
}
config = ma_sound_config_init();
config.pDataSource = pSound->pResourceManagerDataSource;
config.flags = flags;
config.pInitialAttachment = pGroup;
result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound);
if (result != MA_SUCCESS) {
ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource);
ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks);
MA_ZERO_OBJECT(pSound);
return result;
}
return MA_SUCCESS;
}
#endif
MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound)
......
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