Commit 5928aa99 authored by David Reid's avatar David Reid

Add support for pre-allocation to engine nodes.

parent bf1b5183
......@@ -1878,8 +1878,14 @@ typedef struct
MA_ATOMIC ma_bool8 isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */
MA_ATOMIC ma_bool8 isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */
MA_ATOMIC ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to (ma_uint8)-1 the engine will use the closest listener. */
/* Memory management. */
void* _pHeap;
ma_bool32 _ownsHeap;
} ma_engine_node;
MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes);
MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode);
MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode);
MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks);
......@@ -12329,60 +12335,139 @@ static ma_node_vtable g_ma_engine_node_vtable__group =
MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */
};
MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode)
static ma_node_config ma_engine_node_base_node_config_init(const ma_engine_node_config* pConfig)
{
ma_node_config baseNodeConfig;
if (pConfig->type == ma_engine_node_type_sound) {
/* Sound. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__sound;
baseNodeConfig.initialState = ma_node_state_stopped; /* Sounds are stopped by default. */
} else {
/* Group. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__group;
baseNodeConfig.initialState = ma_node_state_started; /* Groups are started by default. */
}
return baseNodeConfig;
}
static ma_spatializer_config ma_engine_node_spatializer_config_init(const ma_node_config* pBaseNodeConfig)
{
return ma_spatializer_config_init(pBaseNodeConfig->pInputChannels[0], pBaseNodeConfig->pOutputChannels[0]);
}
typedef struct
{
size_t sizeInBytes;
size_t baseNodeOffset;
size_t spatializerOffset;
} ma_engine_node_heap_layout;
static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pConfig, ma_engine_node_heap_layout* pHeapLayout)
{
ma_result result;
size_t tempHeapSize;
ma_node_config baseNodeConfig;
ma_resampler_config resamplerConfig;
ma_fader_config faderConfig;
ma_spatializer_config spatializerConfig;
ma_panner_config pannerConfig;
ma_uint32 channelsIn;
ma_uint32 channelsOut;
if (pEngineNode == NULL) {
return MA_INVALID_ARGS;
}
MA_ASSERT(pHeapLayout);
MA_ZERO_OBJECT(pEngineNode);
MA_ZERO_OBJECT(pHeapLayout);
if (pConfig == NULL) {
return MA_INVALID_ARGS; /* Config must be specified. */
return MA_INVALID_ARGS;
}
if (pConfig->pEngine == NULL) {
return MA_INVALID_ARGS; /* An engine must be specified. */
}
if (pConfig->pinnedListenerIndex != (ma_uint8)-1 && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) {
return MA_INVALID_ARGS; /* Invalid listener. */
}
pHeapLayout->sizeInBytes = 0;
/* Assume the engine channel count if no channels were specified. */
channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine);
channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine);
if (pConfig->type == ma_engine_node_type_sound) {
/* Sound. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__sound;
baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pOutputChannels = &channelsOut;
baseNodeConfig.initialState = ma_node_state_stopped; /* Sounds are stopped by default. */
} else {
/* Group. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__group;
baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pOutputChannels = &channelsOut;
baseNodeConfig.initialState = ma_node_state_started; /* Groups are started by default. */
/* Base node. */
baseNodeConfig = ma_engine_node_base_node_config_init(pConfig);
baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pOutputChannels = &channelsOut;
pHeapLayout->baseNodeOffset = pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes += 0; /* TODO: Implement pre-allocation for nodes. */
/* Spatializer. */
spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig);
result = ma_spatializer_get_heap_size(&spatializerConfig, &tempHeapSize);
if (result != MA_SUCCESS) {
return result; /* Failed to retrieve the size of the heap for the spatializer. */
}
result = ma_node_init(&pConfig->pEngine->nodeGraph, &baseNodeConfig, pAllocationCallbacks, &pEngineNode->baseNode);
pHeapLayout->spatializerOffset = pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes += tempHeapSize;
return MA_SUCCESS;
}
MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes)
{
ma_result result;
ma_engine_node_heap_layout heapLayout;
if (pHeapSizeInBytes == NULL) {
return MA_INVALID_ARGS;
}
*pHeapSizeInBytes = 0;
result = ma_engine_node_get_heap_layout(pConfig, &heapLayout);
if (result != MA_SUCCESS) {
goto error0;
return result;
}
*pHeapSizeInBytes = heapLayout.sizeInBytes;
return MA_SUCCESS;
}
MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode)
{
ma_result result;
ma_engine_node_heap_layout heapLayout;
ma_node_config baseNodeConfig;
ma_resampler_config resamplerConfig;
ma_fader_config faderConfig;
ma_spatializer_config spatializerConfig;
ma_panner_config pannerConfig;
ma_uint32 channelsIn;
ma_uint32 channelsOut;
if (pEngineNode == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pEngineNode);
result = ma_engine_node_get_heap_layout(pConfig, &heapLayout);
if (result != MA_SUCCESS) {
return result;
}
if (pConfig->pinnedListenerIndex != (ma_uint8)-1 && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) {
return MA_INVALID_ARGS; /* Invalid listener. */
}
pEngineNode->_pHeap = pHeap;
pEngineNode->pEngine = pConfig->pEngine;
pEngineNode->sampleRate = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine);
pEngineNode->pitch = 1;
......@@ -12392,6 +12477,22 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const
pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled;
pEngineNode->pinnedListenerIndex = pConfig->pinnedListenerIndex;
channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine);
channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine);
/* Base node. */
baseNodeConfig = ma_engine_node_base_node_config_init(pConfig);
baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pOutputChannels = &channelsOut;
result = ma_node_init(&pConfig->pEngine->nodeGraph, &baseNodeConfig, &pEngineNode->pEngine->allocationCallbacks, &pEngineNode->baseNode); /* TODO: Implement pre-allocation for nodes. */
if (result != MA_SUCCESS) {
goto error0;
}
/*
We can now initialize the effects we need in order to implement the engine node. There's a
defined order of operations here, mainly centered around when we convert our channels from the
......@@ -12423,10 +12524,10 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const
Spatialization comes next. We spatialize based ont he node's output channel count. It's up the caller to
ensure channels counts link up correctly in the node graph.
*/
spatializerConfig = ma_spatializer_config_init(baseNodeConfig.pInputChannels[0], baseNodeConfig.pOutputChannels[0]);
spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig);
spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames;
result = ma_spatializer_init(&spatializerConfig, pAllocationCallbacks, &pEngineNode->spatializer); /* TODO: Use a preallocated heap for this. */
result = ma_spatializer_init_preallocated(&spatializerConfig, ma_offset_ptr(pHeap, heapLayout.spatializerOffset), &pEngineNode->spatializer);
if (result != MA_SUCCESS) {
goto error2;
}
......@@ -12440,16 +12541,47 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const
result = ma_panner_init(&pannerConfig, &pEngineNode->panner);
if (result != MA_SUCCESS) {
goto error2;
goto error3;
}
return MA_SUCCESS;
error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */
error2: ma_resampler_uninit(&pEngineNode->resampler);
error1: ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks);
error1: ma_node_uninit(&pEngineNode->baseNode, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */
error0: return result;
}
MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode)
{
ma_result result;
size_t heapSizeInBytes;
void* pHeap;
result = ma_engine_node_get_heap_size(pConfig, &heapSizeInBytes);
if (result != MA_SUCCESS) {
return result;
}
if (heapSizeInBytes > 0) {
pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
if (pHeap == NULL) {
return MA_OUT_OF_MEMORY;
}
} else {
pHeap = NULL;
}
result = ma_engine_node_init_preallocated(pConfig, pHeap, pEngineNode);
if (result != MA_SUCCESS) {
ma_free(pHeap, pAllocationCallbacks);
return result;
}
pEngineNode->_ownsHeap = MA_TRUE;
return MA_SUCCESS;
}
MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks)
{
/*
......@@ -12459,7 +12591,13 @@ MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocati
ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks);
/* Now that the node has been uninitialized we can safely uninitialize the rest. */
ma_spatializer_uninit(&pEngineNode->spatializer, NULL);
ma_resampler_uninit(&pEngineNode->resampler);
/* Free the heap last. */
if (pEngineNode->_pHeap != NULL && pEngineNode->_ownsHeap) {
ma_free(pEngineNode->_pHeap, pAllocationCallbacks);
}
}
......
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