Commit eac61ddc authored by David Reid's avatar David Reid

All the engine to be used with MA_NO_DEVICE_IO.

This allows the engine to be used independent of a device which might
be useful for tools.
parent 0b880d6a
...@@ -8574,7 +8574,7 @@ struct ma_node_graph ...@@ -8574,7 +8574,7 @@ struct ma_node_graph
MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph); MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph);
MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph); MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph);
MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead); MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph); MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph);
MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph); MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph);
MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime); MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime);
...@@ -8838,7 +8838,7 @@ MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode); ...@@ -8838,7 +8838,7 @@ MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode);
Engine Engine
************************************************************************************************************************************************************/ ************************************************************************************************************************************************************/
#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) && !defined(MA_NO_DEVICE_IO) #if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH)
typedef struct ma_engine ma_engine; typedef struct ma_engine ma_engine;
typedef struct ma_sound ma_sound; typedef struct ma_sound ma_sound;
...@@ -8961,8 +8961,11 @@ typedef struct ...@@ -8961,8 +8961,11 @@ typedef struct
#if !defined(MA_NO_RESOURCE_MANAGER) #if !defined(MA_NO_RESOURCE_MANAGER)
ma_resource_manager* pResourceManager; /* Can be null in which case a resource manager will be created for you. */ ma_resource_manager* pResourceManager; /* Can be null in which case a resource manager will be created for you. */
#endif #endif
#if !defined(MA_NO_DEVICE_IO)
ma_context* pContext; ma_context* pContext;
ma_device* pDevice; /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */ ma_device* pDevice; /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */
ma_device_id* pPlaybackDeviceID; /* The ID of the playback device to use with the default listener. */
#endif
ma_log* pLog; /* When set to NULL, will use the context's log. */ ma_log* pLog; /* When set to NULL, will use the context's log. */
ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */ ma_uint32 listenerCount; /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */
ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */ ma_uint32 channels; /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */
...@@ -8971,7 +8974,6 @@ typedef struct ...@@ -8971,7 +8974,6 @@ typedef struct
ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */ ma_uint32 periodSizeInMilliseconds; /* Used if periodSizeInFrames is unset. */
ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */
ma_uint32 gainSmoothTimeInMilliseconds; /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */ ma_uint32 gainSmoothTimeInMilliseconds; /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */
ma_device_id* pPlaybackDeviceID; /* The ID of the playback device to use with the default listener. */
ma_allocation_callbacks allocationCallbacks; ma_allocation_callbacks allocationCallbacks;
ma_bool32 noAutoStart; /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */ ma_bool32 noAutoStart; /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */
ma_vfs* pResourceManagerVFS; /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */ ma_vfs* pResourceManagerVFS; /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */
...@@ -8986,14 +8988,17 @@ struct ma_engine ...@@ -8986,14 +8988,17 @@ struct ma_engine
#if !defined(MA_NO_RESOURCE_MANAGER) #if !defined(MA_NO_RESOURCE_MANAGER)
ma_resource_manager* pResourceManager; ma_resource_manager* pResourceManager;
#endif #endif
#if !defined(MA_NO_DEVICE_IO)
ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */
#endif
ma_log* pLog; ma_log* pLog;
ma_uint32 sampleRate;
ma_uint32 listenerCount; ma_uint32 listenerCount;
ma_spatializer_listener listeners[MA_ENGINE_MAX_LISTENERS]; ma_spatializer_listener listeners[MA_ENGINE_MAX_LISTENERS];
ma_allocation_callbacks allocationCallbacks; ma_allocation_callbacks allocationCallbacks;
ma_bool8 ownsResourceManager; ma_bool8 ownsResourceManager;
ma_bool8 ownsDevice; ma_bool8 ownsDevice;
ma_mutex inlinedSoundLock; /* For synchronizing access so the inlined sound list. */ ma_spinlock inlinedSoundLock; /* For synchronizing access so the inlined sound list. */
ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */
MA_ATOMIC ma_uint32 inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ MA_ATOMIC ma_uint32 inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */
ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */
...@@ -9001,7 +9006,7 @@ struct ma_engine ...@@ -9001,7 +9006,7 @@ struct ma_engine
MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine); MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine);
MA_API void ma_engine_uninit(ma_engine* pEngine); MA_API void ma_engine_uninit(ma_engine* pEngine);
MA_API void ma_engine_data_callback(ma_engine* pEngine, void* pOutput, const void* pInput, ma_uint32 frameCount); MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_device* ma_engine_get_device(ma_engine* pEngine); MA_API ma_device* ma_engine_get_device(ma_engine* pEngine);
MA_API ma_log* ma_engine_get_log(ma_engine* pEngine); MA_API ma_log* ma_engine_get_log(ma_engine* pEngine);
MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine); MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine);
...@@ -64751,10 +64756,10 @@ MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph) ...@@ -64751,10 +64756,10 @@ MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph)
return &pNodeGraph->endpoint; return &pNodeGraph->endpoint;
} }
MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead) MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_uint32 totalFramesRead; ma_uint64 totalFramesRead;
ma_uint32 channels; ma_uint32 channels;
if (pFramesRead != NULL) { if (pFramesRead != NULL) {
...@@ -64772,11 +64777,15 @@ MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* ...@@ -64772,11 +64777,15 @@ MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void*
totalFramesRead = 0; totalFramesRead = 0;
while (totalFramesRead < frameCount) { while (totalFramesRead < frameCount) {
ma_uint32 framesJustRead; ma_uint32 framesJustRead;
ma_uint32 framesToRead = frameCount - totalFramesRead; ma_uint64 framesToRead = frameCount - totalFramesRead;
if (framesToRead > 0xFFFFFFFF) {
framesToRead = 0xFFFFFFFF;
}
ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE); ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE);
{ {
result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint)); result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (ma_uint32)framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint));
} }
ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE); ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE);
...@@ -67422,8 +67431,7 @@ MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode) ...@@ -67422,8 +67431,7 @@ MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode)
#endif /* MA_NO_NODE_GRAPH */ #endif /* MA_NO_NODE_GRAPH */
#if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH) && !defined(MA_NO_DEVICE_IO) #if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH)
/************************************************************************************************************************************************************** /**************************************************************************************************************************************************************
Engine Engine
...@@ -68141,10 +68149,13 @@ MA_API ma_engine_config ma_engine_config_init(void) ...@@ -68141,10 +68149,13 @@ MA_API ma_engine_config ma_engine_config_init(void)
} }
#if !defined(MA_NO_DEVICE_IO)
static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{ {
ma_engine* pEngine = (ma_engine*)pDevice->pUserData; ma_engine* pEngine = (ma_engine*)pDevice->pUserData;
(void)pFramesIn;
/* /*
Experiment: Try processing a resource manager job if we're on the Emscripten build. Experiment: Try processing a resource manager job if we're on the Emscripten build.
...@@ -68169,8 +68180,9 @@ static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOu ...@@ -68169,8 +68180,9 @@ static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOu
} }
#endif #endif
ma_engine_data_callback(pEngine, pFramesOut, pFramesIn, frameCount); ma_engine_read_pcm_frames(pEngine, pFramesOut, frameCount, NULL);
} }
#endif
MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine) MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine)
{ {
...@@ -68191,74 +68203,93 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -68191,74 +68203,93 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
engineConfig = ma_engine_config_init(); engineConfig = ma_engine_config_init();
} }
#if !defined(MA_NO_RESOURCE_MANAGER)
pEngine->pResourceManager = engineConfig.pResourceManager;
#endif
pEngine->pDevice = engineConfig.pDevice;
ma_allocation_callbacks_init_copy(&pEngine->allocationCallbacks, &engineConfig.allocationCallbacks); ma_allocation_callbacks_init_copy(&pEngine->allocationCallbacks, &engineConfig.allocationCallbacks);
/* If we don't have a device, we need one. */ #if !defined(MA_NO_RESOURCE_MANAGER)
if (pEngine->pDevice == NULL) { {
ma_device_config deviceConfig; pEngine->pResourceManager = engineConfig.pResourceManager;
}
#endif
pEngine->pDevice = (ma_device*)ma_malloc(sizeof(*pEngine->pDevice), &pEngine->allocationCallbacks); #if !defined(MA_NO_DEVICE_IO)
{
pEngine->pDevice = engineConfig.pDevice;
/* If we don't have a device, we need one. */
if (pEngine->pDevice == NULL) { if (pEngine->pDevice == NULL) {
return MA_OUT_OF_MEMORY; ma_device_config deviceConfig;
}
deviceConfig = ma_device_config_init(ma_device_type_playback); pEngine->pDevice = (ma_device*)ma_malloc(sizeof(*pEngine->pDevice), &pEngine->allocationCallbacks);
deviceConfig.playback.pDeviceID = engineConfig.pPlaybackDeviceID; if (pEngine->pDevice == NULL) {
deviceConfig.playback.format = ma_format_f32; return MA_OUT_OF_MEMORY;
deviceConfig.playback.channels = engineConfig.channels; }
deviceConfig.sampleRate = engineConfig.sampleRate;
deviceConfig.dataCallback = ma_engine_data_callback_internal; deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.pUserData = pEngine; deviceConfig.playback.pDeviceID = engineConfig.pPlaybackDeviceID;
deviceConfig.periodSizeInFrames = engineConfig.periodSizeInFrames; deviceConfig.playback.format = ma_format_f32;
deviceConfig.periodSizeInMilliseconds = engineConfig.periodSizeInMilliseconds; deviceConfig.playback.channels = engineConfig.channels;
deviceConfig.noPreSilencedOutputBuffer = MA_TRUE; /* We'll always be outputting to every frame in the callback so there's no need for a pre-silenced buffer. */ deviceConfig.sampleRate = engineConfig.sampleRate;
deviceConfig.noClip = MA_TRUE; /* The mixing engine will do clipping itself. */ deviceConfig.dataCallback = ma_engine_data_callback_internal;
deviceConfig.pUserData = pEngine;
if (engineConfig.pContext == NULL) { deviceConfig.periodSizeInFrames = engineConfig.periodSizeInFrames;
ma_context_config contextConfig = ma_context_config_init(); deviceConfig.periodSizeInMilliseconds = engineConfig.periodSizeInMilliseconds;
contextConfig.allocationCallbacks = pEngine->allocationCallbacks; deviceConfig.noPreSilencedOutputBuffer = MA_TRUE; /* We'll always be outputting to every frame in the callback so there's no need for a pre-silenced buffer. */
contextConfig.pLog = engineConfig.pLog; deviceConfig.noClip = MA_TRUE; /* The engine will do clipping itself. */
/* If the engine config does not specify a log, use the resource manager's if we have one. */ if (engineConfig.pContext == NULL) {
#ifndef MA_NO_RESOURCE_MANAGER ma_context_config contextConfig = ma_context_config_init();
{ contextConfig.allocationCallbacks = pEngine->allocationCallbacks;
if (contextConfig.pLog == NULL && engineConfig.pResourceManager != NULL) { contextConfig.pLog = engineConfig.pLog;
contextConfig.pLog = ma_resource_manager_get_log(engineConfig.pResourceManager);
/* If the engine config does not specify a log, use the resource manager's if we have one. */
#ifndef MA_NO_RESOURCE_MANAGER
{
if (contextConfig.pLog == NULL && engineConfig.pResourceManager != NULL) {
contextConfig.pLog = ma_resource_manager_get_log(engineConfig.pResourceManager);
}
} }
#endif
result = ma_device_init_ex(NULL, 0, &contextConfig, &deviceConfig, pEngine->pDevice);
} else {
result = ma_device_init(engineConfig.pContext, &deviceConfig, pEngine->pDevice);
} }
#endif
result = ma_device_init_ex(NULL, 0, &contextConfig, &deviceConfig, pEngine->pDevice); if (result != MA_SUCCESS) {
} else { ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
result = ma_device_init(engineConfig.pContext, &deviceConfig, pEngine->pDevice); pEngine->pDevice = NULL;
} return result;
}
if (result != MA_SUCCESS) { pEngine->ownsDevice = MA_TRUE;
ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
pEngine->pDevice = NULL;
return result;
} }
pEngine->ownsDevice = MA_TRUE; /* Update the channel count and sample rate of the engine config so we can reference it below. */
engineConfig.channels = pEngine->pDevice->playback.channels;
engineConfig.sampleRate = pEngine->pDevice->sampleRate;
} }
#endif
/* pEngine->sampleRate = engineConfig.sampleRate;
The engine always uses either the log that was passed into the config, or the context's log. Either
way, the engine never has ownership of the log. /* The engine always uses either the log that was passed into the config, or the context's log is available. */
*/
if (engineConfig.pLog != NULL) { if (engineConfig.pLog != NULL) {
pEngine->pLog = engineConfig.pLog; pEngine->pLog = engineConfig.pLog;
} else { } else {
pEngine->pLog = ma_device_get_log(pEngine->pDevice); #if !defined(MA_NO_DEVICE_IO)
{
pEngine->pLog = ma_device_get_log(pEngine->pDevice);
}
#else
{
pEngine->pLog = NULL;
}
#endif
} }
/* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */ /* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */
nodeGraphConfig = ma_node_graph_config_init(pEngine->pDevice->playback.channels); nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels);
result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph); result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -68277,7 +68308,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -68277,7 +68308,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
} }
for (iListener = 0; iListener < engineConfig.listenerCount; iListener += 1) { for (iListener = 0; iListener < engineConfig.listenerCount; iListener += 1) {
listenerConfig = ma_spatializer_listener_config_init(pEngine->pDevice->playback.channels); listenerConfig = ma_spatializer_listener_config_init(ma_node_graph_get_channels(&pEngine->nodeGraph));
result = ma_spatializer_listener_init(&listenerConfig, &pEngine->allocationCallbacks, &pEngine->listeners[iListener]); /* TODO: Change this to a pre-allocated heap. */ result = ma_spatializer_listener_init(&listenerConfig, &pEngine->allocationCallbacks, &pEngine->listeners[iListener]); /* TODO: Change this to a pre-allocated heap. */
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -68339,7 +68370,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -68339,7 +68370,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
#endif #endif
/* Setup some stuff for inlined sounds. That is sounds played with ma_engine_play_sound(). */ /* Setup some stuff for inlined sounds. That is sounds played with ma_engine_play_sound(). */
ma_mutex_init(&pEngine->inlinedSoundLock); pEngine->inlinedSoundLock = 0;
pEngine->pInlinedSoundHead = NULL; pEngine->pInlinedSoundHead = NULL;
/* Start the engine if required. This should always be the last step. */ /* Start the engine if required. This should always be the last step. */
...@@ -68353,8 +68384,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -68353,8 +68384,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
return MA_SUCCESS; return MA_SUCCESS;
on_error_4: on_error_4:
ma_mutex_uninit(&pEngine->inlinedSoundLock); #if !defined(MA_NO_RESOURCE_MANAGER)
#ifndef MA_NO_RESOURCE_MANAGER
on_error_3: on_error_3:
if (pEngine->ownsResourceManager) { if (pEngine->ownsResourceManager) {
ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks); ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks);
...@@ -68367,10 +68397,14 @@ on_error_2: ...@@ -68367,10 +68397,14 @@ on_error_2:
ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks); ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks);
on_error_1: on_error_1:
if (pEngine->ownsDevice) { #if !defined(MA_NO_DEVICE_IO)
ma_device_uninit(pEngine->pDevice); {
ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); if (pEngine->ownsDevice) {
ma_device_uninit(pEngine->pDevice);
ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
}
} }
#endif
return result; return result;
} }
...@@ -68384,18 +68418,22 @@ MA_API void ma_engine_uninit(ma_engine* pEngine) ...@@ -68384,18 +68418,22 @@ MA_API void ma_engine_uninit(ma_engine* pEngine)
} }
/* The device must be uninitialized before the node graph to ensure the audio thread doesn't try accessing it. */ /* The device must be uninitialized before the node graph to ensure the audio thread doesn't try accessing it. */
if (pEngine->ownsDevice) { #if !defined(MA_NO_DEVICE_IO)
ma_device_uninit(pEngine->pDevice); {
ma_free(pEngine->pDevice, &pEngine->allocationCallbacks); if (pEngine->ownsDevice) {
} else { ma_device_uninit(pEngine->pDevice);
ma_device_stop(pEngine->pDevice); ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
} else {
ma_device_stop(pEngine->pDevice);
}
} }
#endif
/* /*
All inlined sounds need to be deleted. I'm going to use a lock here just to future proof in case All inlined sounds need to be deleted. I'm going to use a lock here just to future proof in case
I want to do some kind of garbage collection later on. I want to do some kind of garbage collection later on.
*/ */
ma_mutex_lock(&pEngine->inlinedSoundLock); ma_spinlock_lock(&pEngine->inlinedSoundLock);
{ {
for (;;) { for (;;) {
ma_sound_inlined* pSoundToDelete = pEngine->pInlinedSoundHead; ma_sound_inlined* pSoundToDelete = pEngine->pInlinedSoundHead;
...@@ -68409,8 +68447,7 @@ MA_API void ma_engine_uninit(ma_engine* pEngine) ...@@ -68409,8 +68447,7 @@ MA_API void ma_engine_uninit(ma_engine* pEngine)
ma_free(pSoundToDelete, &pEngine->allocationCallbacks); ma_free(pSoundToDelete, &pEngine->allocationCallbacks);
} }
} }
ma_mutex_unlock(&pEngine->inlinedSoundLock); ma_spinlock_unlock(&pEngine->inlinedSoundLock);
ma_mutex_uninit(&pEngine->inlinedSoundLock);
for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) { for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) {
ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks); ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks);
...@@ -68428,11 +68465,9 @@ MA_API void ma_engine_uninit(ma_engine* pEngine) ...@@ -68428,11 +68465,9 @@ MA_API void ma_engine_uninit(ma_engine* pEngine)
#endif #endif
} }
MA_API void ma_engine_data_callback(ma_engine* pEngine, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{ {
(void)pFramesIn; /* Unused. */ return ma_node_graph_read_pcm_frames(&pEngine->nodeGraph, pFramesOut, frameCount, pFramesRead);
ma_node_graph_read_pcm_frames(&pEngine->nodeGraph, pFramesOut, frameCount, NULL);
} }
MA_API ma_device* ma_engine_get_device(ma_engine* pEngine) MA_API ma_device* ma_engine_get_device(ma_engine* pEngine)
...@@ -68441,7 +68476,15 @@ MA_API ma_device* ma_engine_get_device(ma_engine* pEngine) ...@@ -68441,7 +68476,15 @@ MA_API ma_device* ma_engine_get_device(ma_engine* pEngine)
return NULL; return NULL;
} }
return pEngine->pDevice; #if !defined(MA_NO_DEVICE_IO)
{
return pEngine->pDevice;
}
#else
{
return NULL;
}
#endif
} }
MA_API ma_log* ma_engine_get_log(ma_engine* pEngine) MA_API ma_log* ma_engine_get_log(ma_engine* pEngine)
...@@ -68453,7 +68496,15 @@ MA_API ma_log* ma_engine_get_log(ma_engine* pEngine) ...@@ -68453,7 +68496,15 @@ MA_API ma_log* ma_engine_get_log(ma_engine* pEngine)
if (pEngine->pLog != NULL) { if (pEngine->pLog != NULL) {
return pEngine->pLog; return pEngine->pLog;
} else { } else {
return ma_device_get_log(ma_engine_get_device(pEngine)); #if !defined(MA_NO_DEVICE_IO)
{
return ma_device_get_log(ma_engine_get_device(pEngine));
}
#else
{
return NULL;
}
#endif
} }
} }
...@@ -68483,11 +68534,7 @@ MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine) ...@@ -68483,11 +68534,7 @@ MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine)
return 0; return 0;
} }
if (pEngine->pDevice != NULL) { return pEngine->sampleRate;
return pEngine->pDevice->sampleRate;
} else {
return 0; /* No device. */
}
} }
...@@ -68499,7 +68546,16 @@ MA_API ma_result ma_engine_start(ma_engine* pEngine) ...@@ -68499,7 +68546,16 @@ MA_API ma_result ma_engine_start(ma_engine* pEngine)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
result = ma_device_start(pEngine->pDevice); #if !defined(MA_NO_DEVICE_IO)
{
result = ma_device_start(pEngine->pDevice);
}
#else
{
result = MA_INVALID_OPERATION; /* Device IO is disabled, so there's no real notion of "starting" the engine. */
}
#endif
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -68515,7 +68571,16 @@ MA_API ma_result ma_engine_stop(ma_engine* pEngine) ...@@ -68515,7 +68571,16 @@ MA_API ma_result ma_engine_stop(ma_engine* pEngine)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
result = ma_device_stop(pEngine->pDevice); #if !defined(MA_NO_DEVICE_IO)
{
result = ma_device_stop(pEngine->pDevice);
}
#else
{
result = MA_INVALID_OPERATION; /* Device IO is disabled, so there's no real notion of "stopping" the engine. */
}
#endif
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -68529,7 +68594,7 @@ MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume) ...@@ -68529,7 +68594,7 @@ MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
return ma_device_set_master_volume(pEngine->pDevice, volume); return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, volume);
} }
MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB) MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB)
...@@ -68538,7 +68603,7 @@ MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB) ...@@ -68538,7 +68603,7 @@ MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
return ma_device_set_master_gain_db(pEngine->pDevice, gainDB); return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, ma_gain_db_to_factor(gainDB));
} }
...@@ -68702,7 +68767,7 @@ MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePa ...@@ -68702,7 +68767,7 @@ MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePa
simultaneously as we don't ever actually free the sound objects. Some kind of garbage simultaneously as we don't ever actually free the sound objects. Some kind of garbage
collection routine might be valuable for this which I'll think about. collection routine might be valuable for this which I'll think about.
*/ */
ma_mutex_lock(&pEngine->inlinedSoundLock); ma_spinlock_lock(&pEngine->inlinedSoundLock);
{ {
ma_uint32 soundFlags = 0; ma_uint32 soundFlags = 0;
...@@ -68774,7 +68839,7 @@ MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePa ...@@ -68774,7 +68839,7 @@ MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePa
result = MA_OUT_OF_MEMORY; result = MA_OUT_OF_MEMORY;
} }
} }
ma_mutex_unlock(&pEngine->inlinedSoundLock); ma_spinlock_unlock(&pEngine->inlinedSoundLock);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
...@@ -56,7 +56,7 @@ ma_result do_conversion(ma_decoder* pDecoder, ma_encoder* pEncoder) ...@@ -56,7 +56,7 @@ ma_result do_conversion(ma_decoder* pDecoder, ma_encoder* pEncoder)
} }
/* At this point we have the raw data from the decoder. We now just need to write it to the encoder. */ /* At this point we have the raw data from the decoder. We now just need to write it to the encoder. */
ma_encoder_write_pcm_frames(pEncoder, pRawData, framesReadThisIteration); ma_encoder_write_pcm_frames(pEncoder, pRawData, framesReadThisIteration, NULL);
/* Get out of the loop if we've reached the end. */ /* Get out of the loop if we've reached the end. */
if (framesReadThisIteration < framesToReadThisIteration) { if (framesReadThisIteration < framesToReadThisIteration) {
......
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