Commit 95ded1d5 authored by David Reid's avatar David Reid

Fix sound uninitialization.

parent ce4d4b35
...@@ -39,7 +39,11 @@ int main(int argc, char** argv) ...@@ -39,7 +39,11 @@ int main(int argc, char** argv)
ma_engine_sound_set_looping(&engine, &sound, MA_TRUE); ma_engine_sound_set_looping(&engine, &sound, MA_TRUE);
ma_engine_sound_start(&engine, &sound); ma_engine_sound_start(&engine, &sound);
ma_engine_play_sound(&engine, argv[1], NULL);
ma_engine_play_sound(&engine, argv[2], NULL);
ma_engine_play_sound(&engine, argv[3], NULL);
#if 0
float pitch = 1; float pitch = 1;
float pitchStep = 0.01f; float pitchStep = 0.01f;
float pitchMin = 0.125f; float pitchMin = 0.125f;
...@@ -59,6 +63,7 @@ int main(int argc, char** argv) ...@@ -59,6 +63,7 @@ int main(int argc, char** argv)
Sleep(1); Sleep(1);
} }
#endif
printf("Press Enter to quit..."); printf("Press Enter to quit...");
getchar(); getchar();
......
...@@ -135,7 +135,7 @@ Resource Manager Data Source Flags ...@@ -135,7 +135,7 @@ Resource Manager Data Source Flags
================================== ==================================
The flags below are used for controlling how the resource manager should handle the loading and caching of data sources. The flags below are used for controlling how the resource manager should handle the loading and caching of data sources.
*/ */
#define MA_DATA_SOURCE_FLAG_DECODE 0x00000001 /* Decode data before storing in memory. When set, decoding happens on the resource manager thread rather than the mixing thread. Results in faster mixing, but higher memory usage. */ #define MA_DATA_SOURCE_FLAG_DECODE 0x00000001 /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */
#define MA_DATA_SOURCE_FLAG_STREAM 0x00000002 /* When set, does not load the entire data source in memory. Disk I/O will happen on the resource manager thread. */ #define MA_DATA_SOURCE_FLAG_STREAM 0x00000002 /* When set, does not load the entire data source in memory. Disk I/O will happen on the resource manager thread. */
#define MA_DATA_SOURCE_FLAG_ASYNC 0x00000004 /* When set, the resource manager will load the data source asynchronously. */ #define MA_DATA_SOURCE_FLAG_ASYNC 0x00000004 /* When set, the resource manager will load the data source asynchronously. */
...@@ -203,6 +203,7 @@ struct ma_resource_manager_node ...@@ -203,6 +203,7 @@ struct ma_resource_manager_node
ma_decoded_data decoded; ma_decoded_data decoded;
ma_encoded_data encoded; ma_encoded_data encoded;
} data; } data;
ma_bool32 isDataOwnedByResourceManager;
ma_resource_manager_node* pParent; ma_resource_manager_node* pParent;
ma_resource_manager_node* pChildLo; ma_resource_manager_node* pChildLo;
ma_resource_manager_node* pChildHi; ma_resource_manager_node* pChildHi;
...@@ -468,9 +469,9 @@ MA_API ma_result ma_engine_sound_set_volume(ma_engine* pEngine, ma_sound* pSound ...@@ -468,9 +469,9 @@ MA_API ma_result ma_engine_sound_set_volume(ma_engine* pEngine, ma_sound* pSound
MA_API ma_result ma_engine_sound_set_gain_db(ma_engine* pEngine, ma_sound* pSound, float gainDB); MA_API ma_result ma_engine_sound_set_gain_db(ma_engine* pEngine, ma_sound* pSound, float gainDB);
MA_API ma_result ma_engine_sound_set_pan(ma_engine* pEngine, ma_sound* pSound, float pan); MA_API ma_result ma_engine_sound_set_pan(ma_engine* pEngine, ma_sound* pSound, float pan);
MA_API ma_result ma_engine_sound_set_pitch(ma_engine* pEngine, ma_sound* pSound, float pitch); MA_API ma_result ma_engine_sound_set_pitch(ma_engine* pEngine, ma_sound* pSound, float pitch);
MA_API ma_result ma_engine_sound_set_effect(ma_engine* pEngine, ma_sound* pSound, ma_effect* pEffect);
MA_API ma_result ma_engine_sound_set_position(ma_engine* pEngine, ma_sound* pSound, ma_vec3 position); MA_API ma_result ma_engine_sound_set_position(ma_engine* pEngine, ma_sound* pSound, ma_vec3 position);
MA_API ma_result ma_engine_sound_set_rotation(ma_engine* pEngine, ma_sound* pSound, ma_quat rotation); MA_API ma_result ma_engine_sound_set_rotation(ma_engine* pEngine, ma_sound* pSound, ma_quat rotation);
MA_API ma_result ma_engine_sound_set_effect(ma_engine* pEngine, ma_sound* pSound, ma_effect* pEffect);
MA_API ma_result ma_engine_sound_set_looping(ma_engine* pEngine, ma_sound* pSound, ma_bool32 isLooping); MA_API ma_result ma_engine_sound_set_looping(ma_engine* pEngine, ma_sound* pSound, ma_bool32 isLooping);
MA_API ma_bool32 ma_engine_sound_at_end(ma_engine* pEngine, const ma_sound* pSound); MA_API ma_bool32 ma_engine_sound_at_end(ma_engine* pEngine, const ma_sound* pSound);
MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup); /* Fire and forget. */ MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup); /* Fire and forget. */
...@@ -1267,6 +1268,17 @@ static ma_result ma_resource_manager_data_source_init(ma_resource_manager* pReso ...@@ -1267,6 +1268,17 @@ static ma_result ma_resource_manager_data_source_init(ma_resource_manager* pReso
return MA_SUCCESS; return MA_SUCCESS;
} }
static void ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource)
{
MA_ASSERT(pDataSource != NULL);
if (pDataSource->type == ma_resource_manager_data_source_type_buffer) {
ma_audio_buffer_uninit(&pDataSource->backend.buffer);
} else {
ma_decoder_uninit(&pDataSource->backend.decoder);
}
}
MA_API ma_resource_manager_config ma_resource_manager_config_init(ma_format decodedFormat, ma_uint32 decodedChannels, ma_uint32 decodedSampleRate, const ma_allocation_callbacks* pAllocationCallbacks) MA_API ma_resource_manager_config ma_resource_manager_config_init(ma_format decodedFormat, ma_uint32 decodedChannels, ma_uint32 decodedSampleRate, const ma_allocation_callbacks* pAllocationCallbacks)
...@@ -1571,7 +1583,54 @@ static ma_result ma_resource_manager_acquire_data_node(ma_resource_manager* pRes ...@@ -1571,7 +1583,54 @@ static ma_result ma_resource_manager_acquire_data_node(ma_resource_manager* pRes
return result; return result;
} }
static ma_result ma_resource_manager_release_data_node_nolock(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_uint32* pReferenceCount)
static ma_result ma_resource_manager_release_data_node_nolock(ma_resource_manager* pResourceManager, ma_resource_manager_node* pDataNode, ma_uint32* pReferenceCount)
{
ma_result result;
ma_uint32 refCount;
MA_ASSERT(pResourceManager != NULL);
MA_ASSERT(pDataNode != NULL);
MA_ASSERT(pReferenceCount != NULL);
MA_ASSERT(pDataNode->refCount > 0); /* We should never find the node in the first place if the reference counter is 0. */
refCount = ma_atomic_decrement_32(&pDataNode->refCount);
if (refCount == 0) {
/* Standard node delete. */
result = ma_resource_manager_remove_data_node_nolock(pResourceManager, pDataNode);
if (result != MA_SUCCESS) {
return result; /* This should never happen. */
}
/* We've removed the node from the binary tree so now we can free it's memory. */
ma__free_from_callbacks(pDataNode, &pResourceManager->config.allocationCallbacks);
}
if (pReferenceCount != NULL) {
*pReferenceCount = refCount;
}
return MA_SUCCESS;
}
static ma_result ma_resource_manager_release_data_node(ma_resource_manager* pResourceManager, ma_resource_manager_node* pDataNode, ma_uint32* pReferenceCount)
{
ma_result result;
MA_ASSERT(pResourceManager != NULL);
MA_ASSERT(pDataNode != NULL);
MA_ASSERT(pReferenceCount != NULL);
ma_mutex_lock(&pResourceManager->dataNodeLock);
{
result = ma_resource_manager_release_data_node_nolock(pResourceManager, pDataNode, pReferenceCount);
}
ma_mutex_unlock(&pResourceManager->dataNodeLock);
return result;
}
static ma_result ma_resource_manager_release_data_node_by_name_nolock(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_uint32* pReferenceCount)
{ {
ma_result result; ma_result result;
ma_uint32 refCount; ma_uint32 refCount;
...@@ -1605,7 +1664,7 @@ static ma_result ma_resource_manager_release_data_node_nolock(ma_resource_manage ...@@ -1605,7 +1664,7 @@ static ma_result ma_resource_manager_release_data_node_nolock(ma_resource_manage
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_resource_manager_release_data_node(ma_resource_manager* pResourceManager, const char* pName, ma_uint32* pReferenceCount) static ma_result ma_resource_manager_release_data_node_by_name(ma_resource_manager* pResourceManager, const char* pName, ma_uint32* pReferenceCount)
{ {
ma_result result; ma_result result;
ma_uint32 hashedName32; ma_uint32 hashedName32;
...@@ -1617,7 +1676,7 @@ static ma_result ma_resource_manager_release_data_node(ma_resource_manager* pRes ...@@ -1617,7 +1676,7 @@ static ma_result ma_resource_manager_release_data_node(ma_resource_manager* pRes
ma_mutex_lock(&pResourceManager->dataNodeLock); ma_mutex_lock(&pResourceManager->dataNodeLock);
{ {
result = ma_resource_manager_release_data_node_nolock(pResourceManager, hashedName32, pReferenceCount); result = ma_resource_manager_release_data_node_by_name_nolock(pResourceManager, hashedName32, pReferenceCount);
} }
ma_mutex_unlock(&pResourceManager->dataNodeLock); ma_mutex_unlock(&pResourceManager->dataNodeLock);
...@@ -1702,7 +1761,7 @@ static ma_result ma_resource_manager_register_data(ma_resource_manager* pResourc ...@@ -1702,7 +1761,7 @@ static ma_result ma_resource_manager_register_data(ma_resource_manager* pResourc
return result; return result;
} }
static ma_result ma_resource_manager_register_decoded_data_ex(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_resource_manager_node** ppDataNode) static ma_result ma_resource_manager_register_decoded_data_ex(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_bool32 isOwnedByResourceManager, ma_resource_manager_node** ppDataNode)
{ {
ma_resource_manager_node node; ma_resource_manager_node node;
...@@ -1710,6 +1769,7 @@ static ma_result ma_resource_manager_register_decoded_data_ex(ma_resource_manage ...@@ -1710,6 +1769,7 @@ static ma_result ma_resource_manager_register_decoded_data_ex(ma_resource_manage
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
node.isDataOwnedByResourceManager = isOwnedByResourceManager;
node.type = ma_resource_manager_data_type_decoded; node.type = ma_resource_manager_data_type_decoded;
node.data.decoded.pData = pData; node.data.decoded.pData = pData;
node.data.decoded.frameCount = frameCount; node.data.decoded.frameCount = frameCount;
...@@ -1722,10 +1782,10 @@ static ma_result ma_resource_manager_register_decoded_data_ex(ma_resource_manage ...@@ -1722,10 +1782,10 @@ static ma_result ma_resource_manager_register_decoded_data_ex(ma_resource_manage
MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
{ {
return ma_resource_manager_register_decoded_data_ex(pResourceManager, pName, pData, frameCount, format, channels, sampleRate, NULL); return ma_resource_manager_register_decoded_data_ex(pResourceManager, pName, pData, frameCount, format, channels, sampleRate, MA_FALSE, NULL);
} }
static ma_result ma_resource_manager_register_encoded_data_ex(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes, ma_resource_manager_node** ppDataNode) static ma_result ma_resource_manager_register_encoded_data_ex(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes, ma_bool32 isOwnedByResourceManager, ma_resource_manager_node** ppDataNode)
{ {
ma_resource_manager_node node; ma_resource_manager_node node;
...@@ -1733,6 +1793,7 @@ static ma_result ma_resource_manager_register_encoded_data_ex(ma_resource_manage ...@@ -1733,6 +1793,7 @@ static ma_result ma_resource_manager_register_encoded_data_ex(ma_resource_manage
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
node.isDataOwnedByResourceManager = isOwnedByResourceManager;
node.type = ma_resource_manager_data_type_encoded; node.type = ma_resource_manager_data_type_encoded;
node.data.encoded.pData = pData; node.data.encoded.pData = pData;
node.data.encoded.sizeInBytes = sizeInBytes; node.data.encoded.sizeInBytes = sizeInBytes;
...@@ -1742,12 +1803,12 @@ static ma_result ma_resource_manager_register_encoded_data_ex(ma_resource_manage ...@@ -1742,12 +1803,12 @@ static ma_result ma_resource_manager_register_encoded_data_ex(ma_resource_manage
MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes) MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes)
{ {
return ma_resource_manager_register_encoded_data_ex(pResourceManager, pName, pData, sizeInBytes, NULL); return ma_resource_manager_register_encoded_data_ex(pResourceManager, pName, pData, sizeInBytes, MA_FALSE, NULL);
} }
MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName) MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName)
{ {
return ma_resource_manager_release_data_node(pResourceManager, pName, NULL); return ma_resource_manager_release_data_node_by_name(pResourceManager, pName, NULL);
} }
MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, ma_data_source** ppDataSource) MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, ma_data_source** ppDataSource)
...@@ -1756,9 +1817,6 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe ...@@ -1756,9 +1817,6 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe
ma_resource_manager_node* pDataNode; ma_resource_manager_node* pDataNode;
ma_resource_manager_data_source* pDataSource; ma_resource_manager_data_source* pDataSource;
ma_decoder* pDecoder;
ma_decoder_config decoderConfig;
if (ppDataSource == NULL) { if (ppDataSource == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
...@@ -1798,7 +1856,7 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe ...@@ -1798,7 +1856,7 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe
} }
/* We have the encoded data so now we need to register it. */ /* We have the encoded data so now we need to register it. */
result = ma_resource_manager_register_encoded_data_ex(pResourceManager, pName, pFileData, fileSize, &pDataNode); result = ma_resource_manager_register_encoded_data_ex(pResourceManager, pName, pFileData, fileSize, MA_TRUE, &pDataNode);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma__free_from_callbacks(pFileData, &pResourceManager->config.allocationCallbacks); ma__free_from_callbacks(pFileData, &pResourceManager->config.allocationCallbacks);
return result; return result;
...@@ -1809,8 +1867,7 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe ...@@ -1809,8 +1867,7 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe
ma_uint64 frameCount; ma_uint64 frameCount;
void* pDecodedData; void* pDecodedData;
//config = ma_decoder_config_init(ma_format_unknown, 0, 0); /* For now we'll decode into native format, but we may want to change this to the standard output format. */ config = ma_decoder_config_init(pResourceManager->config.decodedFormat, 0, pResourceManager->config.decodedSampleRate); /* Need to keep the native channel count because we'll be using that for spatialization. */
config = ma_decoder_config_init(pResourceManager->config.decodedFormat, pResourceManager->config.decodedChannels, pResourceManager->config.decodedSampleRate);
config.allocationCallbacks = pResourceManager->config.allocationCallbacks; config.allocationCallbacks = pResourceManager->config.allocationCallbacks;
result = ma_decode_from_vfs(pResourceManager->config.pVFS, pName, &config, &frameCount, &pDecodedData); result = ma_decode_from_vfs(pResourceManager->config.pVFS, pName, &config, &frameCount, &pDecodedData);
...@@ -1819,7 +1876,7 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe ...@@ -1819,7 +1876,7 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe
} }
/* We have the decoded data so now we need to register it. */ /* We have the decoded data so now we need to register it. */
result = ma_resource_manager_register_decoded_data_ex(pResourceManager, pName, pDecodedData, frameCount, config.format, config.channels, config.sampleRate, &pDataNode); result = ma_resource_manager_register_decoded_data_ex(pResourceManager, pName, pDecodedData, frameCount, config.format, config.channels, config.sampleRate, MA_TRUE, &pDataNode);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma__free_from_callbacks(pDecodedData, &pResourceManager->config.allocationCallbacks); ma__free_from_callbacks(pDecodedData, &pResourceManager->config.allocationCallbacks);
return result; return result;
...@@ -1845,41 +1902,41 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe ...@@ -1845,41 +1902,41 @@ MA_API ma_result ma_resource_manager_create_data_source(ma_resource_manager* pRe
*ppDataSource = pDataSource; *ppDataSource = pDataSource;
return MA_SUCCESS; return MA_SUCCESS;
#if 0
/* For testing and prototyping we're just allocating a decoder on the heap. Later on this will be a custom resource manager specific data source. */
pDecoder = ma_malloc(sizeof(*pDecoder), NULL);
if (pDecoder == NULL) {
return MA_OUT_OF_MEMORY;
}
decoderConfig = ma_decoder_config_init(pResourceManager->config.decodedFormat, 0, pResourceManager->config.decodedSampleRate);
result = ma_decoder_init_file(pName, &decoderConfig, pDecoder);
if (result != MA_SUCCESS) {
ma_free(pDecoder, NULL);
return result;
}
*ppDataSource = (ma_data_source*)pDecoder;
return MA_SUCCESS;
#endif
} }
MA_API ma_result ma_resource_manager_delete_data_source(ma_resource_manager* pResourceManager, ma_data_source* pDataSource) MA_API ma_result ma_resource_manager_delete_data_source(ma_resource_manager* pResourceManager, ma_data_source* pDataSource)
{ {
ma_decoder* pDecoder; ma_result result;
ma_resource_manager_data_source* pRMDataSource = (ma_resource_manager_data_source*)pDataSource;
ma_resource_manager_node* pDataNode = NULL;
if (pResourceManager == NULL || pDataSource == NULL) { if (pResourceManager == NULL || pDataSource == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/* Everything is a ma_decoder while we're prototyping. */ /* If the data source is not being streamed we will need to unacquire the data source so the reference counter is decremented. */
pDecoder = (ma_decoder*)pDataSource; pDataNode = pRMDataSource->pDataNode;
ma_decoder_uninit(pDecoder); if (pDataNode != NULL) {
ma_resource_manager_node nodeCopy = *pDataNode; /* We need this so we can keep track of the pointer. */
ma_uint32 refCount;
result = ma_resource_manager_release_data_node(pResourceManager, pDataNode, &refCount);
if (result == MA_SUCCESS) {
if (refCount == 0) {
/* The backing data of the data source needs to be deleted if it's owned by us. */
if (pDataNode->isDataOwnedByResourceManager) {
if (nodeCopy.type == ma_resource_manager_data_type_encoded) {
ma__free_from_callbacks((void*)nodeCopy.data.encoded.pData, &pResourceManager->config.allocationCallbacks); /* MA_ALLOCATION_TYPE_ENCODED_BUFFER */
} else {
ma__free_from_callbacks((void*)nodeCopy.data.decoded.pData, &pResourceManager->config.allocationCallbacks); /* MA_ALLOCATION_TYPE_DECODED_BUFFER */
}
}
}
}
}
ma_free(pDecoder, NULL); /* The data source can now be freed. */
ma_resource_manager_data_source_uninit(pRMDataSource);
ma__free_from_callbacks(pRMDataSource, &pResourceManager->config.allocationCallbacks); /* MA_ALLOCATION_TYPE_RESOURCE_MANAGER_DATA_SOURCE */
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -3182,33 +3239,33 @@ MA_API ma_result ma_engine_sound_set_pan(ma_engine* pEngine, ma_sound* pSound, f ...@@ -3182,33 +3239,33 @@ MA_API ma_result ma_engine_sound_set_pan(ma_engine* pEngine, ma_sound* pSound, f
return ma_panner_set_pan(&pSound->effect.panner, pan); return ma_panner_set_pan(&pSound->effect.panner, pan);
} }
MA_API ma_result ma_engine_sound_set_effect(ma_engine* pEngine, ma_sound* pSound, ma_effect* pEffect) MA_API ma_result ma_engine_sound_set_position(ma_engine* pEngine, ma_sound* pSound, ma_vec3 position)
{ {
if (pEngine == NULL || pSound == NULL) { if (pEngine == NULL || pSound == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
pSound->effect.pPreEffect = pEffect; return ma_spatializer_set_position(&pSound->effect.spatializer, position);
return MA_SUCCESS;
} }
MA_API ma_result ma_engine_sound_set_position(ma_engine* pEngine, ma_sound* pSound, ma_vec3 position) MA_API ma_result ma_engine_sound_set_rotation(ma_engine* pEngine, ma_sound* pSound, ma_quat rotation)
{ {
if (pEngine == NULL || pSound == NULL) { if (pEngine == NULL || pSound == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
return ma_spatializer_set_position(&pSound->effect.spatializer, position); return ma_spatializer_set_rotation(&pSound->effect.spatializer, rotation);
} }
MA_API ma_result ma_engine_sound_set_rotation(ma_engine* pEngine, ma_sound* pSound, ma_quat rotation) MA_API ma_result ma_engine_sound_set_effect(ma_engine* pEngine, ma_sound* pSound, ma_effect* pEffect)
{ {
if (pEngine == NULL || pSound == NULL) { if (pEngine == NULL || pSound == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
return ma_spatializer_set_rotation(&pSound->effect.spatializer, rotation); pSound->effect.pPreEffect = pEffect;
return MA_SUCCESS;
} }
MA_API ma_result ma_engine_sound_set_looping(ma_engine* pEngine, ma_sound* pSound, ma_bool32 isLooping) MA_API ma_result ma_engine_sound_set_looping(ma_engine* pEngine, ma_sound* pSound, ma_bool32 isLooping)
...@@ -3457,6 +3514,22 @@ MA_API ma_result ma_engine_sound_group_init(ma_engine* pEngine, ma_sound_group* ...@@ -3457,6 +3514,22 @@ MA_API ma_result ma_engine_sound_group_init(ma_engine* pEngine, ma_sound_group*
return MA_SUCCESS; return MA_SUCCESS;
} }
static void ma_engine_sound_group_uninit_all_internal_sounds(ma_engine* pEngine, ma_sound_group* pGroup)
{
ma_sound* pCurrentSound;
/* We need to be careful here that we keep our iteration valid. */
pCurrentSound = pGroup->pFirstSoundInGroup;
while (pCurrentSound != NULL) {
ma_sound* pSoundToDelete = pCurrentSound;
pCurrentSound = pCurrentSound->pNextSoundInGroup;
if (pSoundToDelete->_isInternal) {
ma_engine_sound_uninit(pEngine, pSoundToDelete);
}
}
}
MA_API void ma_engine_sound_group_uninit(ma_engine* pEngine, ma_sound_group* pGroup) MA_API void ma_engine_sound_group_uninit(ma_engine* pEngine, ma_sound_group* pGroup)
{ {
ma_result result; ma_result result;
...@@ -3466,6 +3539,9 @@ MA_API void ma_engine_sound_group_uninit(ma_engine* pEngine, ma_sound_group* pGr ...@@ -3466,6 +3539,9 @@ MA_API void ma_engine_sound_group_uninit(ma_engine* pEngine, ma_sound_group* pGr
MA_ASSERT(MA_FALSE); /* Should never happen. Trigger an assert for debugging, but don't stop uninitializing in production to ensure we free memory down below. */ MA_ASSERT(MA_FALSE); /* Should never happen. Trigger an assert for debugging, but don't stop uninitializing in production to ensure we free memory down below. */
} }
/* Any in-place sounds need to be uninitialized. */
ma_engine_sound_group_uninit_all_internal_sounds(pEngine, pGroup);
result = ma_engine_sound_group_detach(pEngine, pGroup); result = ma_engine_sound_group_detach(pEngine, pGroup);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
MA_ASSERT(MA_FALSE); /* As above, should never happen, but just in case trigger an assert in debug mode, but continue processing. */ MA_ASSERT(MA_FALSE); /* As above, should never happen, but just in case trigger an assert in debug mode, but continue processing. */
......
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