Commit d3d4d425 authored by David Reid's avatar David Reid

Version 0.11.1

parent a971840b
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.0 - 2021-12-18 miniaudio - v0.11.1 - 2021-12-27
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -34,6 +34,7 @@ GitHub: https://github.com/mackron/miniaudio ...@@ -34,6 +34,7 @@ GitHub: https://github.com/mackron/miniaudio
#include <string.h> /* For memset() */ #include <string.h> /* For memset() */
#include <sched.h> #include <sched.h>
#include <sys/time.h> /* select() (used for ma_sleep()). */ #include <sys/time.h> /* select() (used for ma_sleep()). */
#include <pthread.h>
#endif #endif
#include <sys/stat.h> /* For fstat(), etc. */ #include <sys/stat.h> /* For fstat(), etc. */
...@@ -4536,7 +4537,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority ...@@ -4536,7 +4537,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority
(void)stackSize; (void)stackSize;
#endif #endif
result = pthread_create(pThread, pAttr, entryProc, pData); result = pthread_create((pthread_t*)pThread, pAttr, entryProc, pData);
/* The thread attributes object is no longer required. */ /* The thread attributes object is no longer required. */
if (pAttr != NULL) { if (pAttr != NULL) {
...@@ -4552,8 +4553,8 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority ...@@ -4552,8 +4553,8 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority
static void ma_thread_wait__posix(ma_thread* pThread) static void ma_thread_wait__posix(ma_thread* pThread)
{ {
pthread_join(*pThread, NULL); pthread_join((pthread_t)*pThread, NULL);
pthread_detach(*pThread); pthread_detach((pthread_t)*pThread);
} }
...@@ -4587,14 +4588,14 @@ static ma_result ma_event_init__posix(ma_event* pEvent) ...@@ -4587,14 +4588,14 @@ static ma_result ma_event_init__posix(ma_event* pEvent)
{ {
int result; int result;
result = pthread_mutex_init(&pEvent->lock, NULL); result = pthread_mutex_init((pthread_mutex_t*)&pEvent->lock, NULL);
if (result != 0) { if (result != 0) {
return ma_result_from_errno(result); return ma_result_from_errno(result);
} }
result = pthread_cond_init(&pEvent->cond, NULL); result = pthread_cond_init((pthread_cond_t*)&pEvent->cond, NULL);
if (result != 0) { if (result != 0) {
pthread_mutex_destroy(&pEvent->lock); pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
return ma_result_from_errno(result); return ma_result_from_errno(result);
} }
...@@ -4604,32 +4605,32 @@ static ma_result ma_event_init__posix(ma_event* pEvent) ...@@ -4604,32 +4605,32 @@ static ma_result ma_event_init__posix(ma_event* pEvent)
static void ma_event_uninit__posix(ma_event* pEvent) static void ma_event_uninit__posix(ma_event* pEvent)
{ {
pthread_cond_destroy(&pEvent->cond); pthread_cond_destroy((pthread_cond_t*)&pEvent->cond);
pthread_mutex_destroy(&pEvent->lock); pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
} }
static ma_result ma_event_wait__posix(ma_event* pEvent) static ma_result ma_event_wait__posix(ma_event* pEvent)
{ {
pthread_mutex_lock(&pEvent->lock); pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
{ {
while (pEvent->value == 0) { while (pEvent->value == 0) {
pthread_cond_wait(&pEvent->cond, &pEvent->lock); pthread_cond_wait((pthread_cond_t*)&pEvent->cond, (pthread_mutex_t*)&pEvent->lock);
} }
pEvent->value = 0; /* Auto-reset. */ pEvent->value = 0; /* Auto-reset. */
} }
pthread_mutex_unlock(&pEvent->lock); pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_event_signal__posix(ma_event* pEvent) static ma_result ma_event_signal__posix(ma_event* pEvent)
{ {
pthread_mutex_lock(&pEvent->lock); pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
{ {
pEvent->value = 1; pEvent->value = 1;
pthread_cond_signal(&pEvent->cond); pthread_cond_signal((pthread_cond_t*)&pEvent->cond);
} }
pthread_mutex_unlock(&pEvent->lock); pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -4645,14 +4646,14 @@ static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemap ...@@ -4645,14 +4646,14 @@ static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemap
pSemaphore->value = initialValue; pSemaphore->value = initialValue;
result = pthread_mutex_init(&pSemaphore->lock, NULL); result = pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock, NULL);
if (result != 0) { if (result != 0) {
return ma_result_from_errno(result); /* Failed to create mutex. */ return ma_result_from_errno(result); /* Failed to create mutex. */
} }
result = pthread_cond_init(&pSemaphore->cond, NULL); result = pthread_cond_init((pthread_cond_t*)&pSemaphore->cond, NULL);
if (result != 0) { if (result != 0) {
pthread_mutex_destroy(&pSemaphore->lock); pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
return ma_result_from_errno(result); /* Failed to create condition variable. */ return ma_result_from_errno(result); /* Failed to create condition variable. */
} }
...@@ -4665,8 +4666,8 @@ static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore) ...@@ -4665,8 +4666,8 @@ static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
return; return;
} }
pthread_cond_destroy(&pSemaphore->cond); pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond);
pthread_mutex_destroy(&pSemaphore->lock); pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
} }
static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore) static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
...@@ -4675,16 +4676,16 @@ static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore) ...@@ -4675,16 +4676,16 @@ static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
pthread_mutex_lock(&pSemaphore->lock); pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
{ {
/* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */ /* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */
while (pSemaphore->value == 0) { while (pSemaphore->value == 0) {
pthread_cond_wait(&pSemaphore->cond, &pSemaphore->lock); pthread_cond_wait((pthread_cond_t*)&pSemaphore->cond, (pthread_mutex_t*)&pSemaphore->lock);
} }
pSemaphore->value -= 1; pSemaphore->value -= 1;
} }
pthread_mutex_unlock(&pSemaphore->lock); pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -4695,12 +4696,12 @@ static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore) ...@@ -4695,12 +4696,12 @@ static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
pthread_mutex_lock(&pSemaphore->lock); pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
{ {
pSemaphore->value += 1; pSemaphore->value += 1;
pthread_cond_signal(&pSemaphore->cond); pthread_cond_signal((pthread_cond_t*)&pSemaphore->cond);
} }
pthread_mutex_unlock(&pSemaphore->lock); pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -4745,7 +4746,7 @@ static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priorit ...@@ -4745,7 +4746,7 @@ static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priorit
ma_thread_proxy_data* pProxyData; ma_thread_proxy_data* pProxyData;
if (pThread == NULL || entryProc == NULL) { if (pThread == NULL || entryProc == NULL) {
return MA_FALSE; return MA_INVALID_ARGS;
} }
pProxyData = (ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData), pAllocationCallbacks); /* Will be freed by the proxy entry proc. */ pProxyData = (ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData), pAllocationCallbacks); /* Will be freed by the proxy entry proc. */
...@@ -24370,8 +24371,9 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf ...@@ -24370,8 +24371,9 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf
ma_result result; ma_result result;
ma_AAudioStreamBuilder* pBuilder; ma_AAudioStreamBuilder* pBuilder;
MA_ASSERT(pConfig != NULL); MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig->deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */ MA_ASSERT(pDescriptor != NULL);
MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */
*ppStream = NULL; *ppStream = NULL;
...@@ -24586,12 +24588,6 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf ...@@ -24586,12 +24588,6 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf
return MA_DEVICE_TYPE_NOT_SUPPORTED; return MA_DEVICE_TYPE_NOT_SUPPORTED;
} }
/* No exclusive mode with AAudio. */
if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture); result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -24731,6 +24727,36 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) ...@@ -24731,6 +24727,36 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice)
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo)
{
ma_AAudioStream* pStream = NULL;
MA_ASSERT(pDevice != NULL);
MA_ASSERT(type != ma_device_type_duplex);
MA_ASSERT(pDeviceInfo != NULL);
if (type == ma_device_type_playback) {
pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamCapture;
pDeviceInfo->id.aaudio = pDevice->capture.id.aaudio;
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */
}
if (type == ma_device_type_capture) {
pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback;
pDeviceInfo->id.aaudio = pDevice->playback.id.aaudio;
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */
}
/* Safety. Should never happen. */
if (pStream == NULL) {
return MA_INVALID_OPERATION;
}
pDeviceInfo->nativeDataFormatCount = 0;
ma_context_add_native_data_format_from_AAudioStream__aaudio(pDevice->pContext, pStream, 0, pDeviceInfo);
return MA_SUCCESS;
}
static ma_result ma_context_uninit__aaudio(ma_context* pContext) static ma_result ma_context_uninit__aaudio(ma_context* pContext)
{ {
...@@ -24802,6 +24828,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ ...@@ -24802,6 +24828,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_
pCallbacks->onDeviceRead = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceRead = NULL; /* Not used because AAudio is asynchronous. */
pCallbacks->onDeviceWrite = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceWrite = NULL; /* Not used because AAudio is asynchronous. */
pCallbacks->onDeviceDataLoop = NULL; /* Not used because AAudio is asynchronous. */ pCallbacks->onDeviceDataLoop = NULL; /* Not used because AAudio is asynchronous. */
pCallbacks->onDeviceGetInfo = ma_device_get_info__aaudio;
(void)pConfig; (void)pConfig;
return MA_SUCCESS; return MA_SUCCESS;
...@@ -25132,6 +25159,7 @@ return_default_device:; ...@@ -25132,6 +25159,7 @@ return_default_device:;
if (cbResult) { if (cbResult) {
ma_device_info deviceInfo; ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo); MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT;
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
} }
...@@ -25140,6 +25168,7 @@ return_default_device:; ...@@ -25140,6 +25168,7 @@ return_default_device:;
if (cbResult) { if (cbResult) {
ma_device_info deviceInfo; ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo); MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
} }
...@@ -25238,10 +25267,12 @@ return_default_device: ...@@ -25238,10 +25267,12 @@ return_default_device:
} }
} }
/* Name / Description */ /* ID and Name / Description */
if (deviceType == ma_device_type_playback) { if (deviceType == ma_device_type_playback) {
pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT;
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
} else { } else {
pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
} }
...@@ -25407,8 +25438,8 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch ...@@ -25407,8 +25438,8 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch
#endif #endif
pDataFormat->numChannels = channels; pDataFormat->numChannels = channels;
((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate) * 1000; /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */ ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */
pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8; pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format) * 8;
pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels); pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels);
pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
...@@ -25535,7 +25566,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf ...@@ -25535,7 +25566,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf
locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE;
locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT;
locatorDevice.deviceID = (pDescriptorCapture->pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pDescriptorCapture->pDeviceID->opensl; locatorDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; /* Must always use the default device with Android. */
locatorDevice.device = NULL; locatorDevice.device = NULL;
source.pLocator = &locatorDevice; source.pLocator = &locatorDevice;
...@@ -25547,14 +25578,14 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf ...@@ -25547,14 +25578,14 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf
sink.pFormat = (SLDataFormat_PCM*)&pcm; sink.pFormat = (SLDataFormat_PCM*)&pcm;
resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) {
/* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
pcm.formatType = SL_DATAFORMAT_PCM; pcm.formatType = SL_DATAFORMAT_PCM;
pcm.numChannels = 1; pcm.numChannels = 1;
((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */ ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
pcm.bitsPerSample = 16; pcm.bitsPerSample = 16;
pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; pcm.channelMask = 0;
resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
} }
...@@ -25670,7 +25701,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf ...@@ -25670,7 +25701,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf
sink.pFormat = NULL; sink.pFormat = NULL;
resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) {
/* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
pcm.formatType = SL_DATAFORMAT_PCM; pcm.formatType = SL_DATAFORMAT_PCM;
pcm.numChannels = 2; pcm.numChannels = 2;
...@@ -27783,7 +27814,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -27783,7 +27814,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
ma_device_info deviceInfo; ma_device_info deviceInfo;
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
result = ma_context_get_device_info(pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, descriptorCapture.pDeviceID, &deviceInfo); result = ma_device_get_info(pDevice, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, &deviceInfo);
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1); ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1);
} else { } else {
...@@ -27797,7 +27828,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -27797,7 +27828,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
} }
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
result = ma_context_get_device_info(pContext, ma_device_type_playback, descriptorPlayback.pDeviceID, &deviceInfo); result = ma_device_get_info(pDevice, ma_device_type_playback, &deviceInfo);
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1); ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1);
} else { } else {
...@@ -27845,34 +27876,44 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -27845,34 +27876,44 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
ma_device__set_state(pDevice, ma_device_state_stopped); ma_device__set_state(pDevice, ma_device_state_stopped);
} }
/* Restricting this to debug output because it's a bit spamy and only really needed for debugging. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); #if defined(MA_DEBUG_OUTPUT)
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", pDevice->capture.name, "Capture"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels); char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate); ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " %s (%s)\n", name, "Capture");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Conversion:\n");
} ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO");
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", pDevice->playback.name, "Playback"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat)); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate); }
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods)); if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Conversion:\n"); char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO"); ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " %s (%s)\n", name, "Playback");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods));
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Conversion:\n");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO");
}
} }
#endif
MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped);
return MA_SUCCESS; return MA_SUCCESS;
...@@ -28012,6 +28053,70 @@ MA_API ma_log* ma_device_get_log(ma_device* pDevice) ...@@ -28012,6 +28053,70 @@ MA_API ma_log* ma_device_get_log(ma_device* pDevice)
return ma_context_get_log(ma_device_get_context(pDevice)); return ma_context_get_log(ma_device_get_context(pDevice));
} }
MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo)
{
if (pDeviceInfo == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pDeviceInfo);
if (pDevice == NULL) {
return MA_INVALID_ARGS;
}
/* If the onDeviceGetInfo() callback is set, use that. Otherwise we'll fall back to ma_context_get_device_info(). */
if (pDevice->pContext->callbacks.onDeviceGetInfo != NULL) {
return pDevice->pContext->callbacks.onDeviceGetInfo(pDevice, type, pDeviceInfo);
}
/* Getting here means onDeviceGetInfo is not implemented so we need to fall back to an alternative. */
if (type == ma_device_type_playback) {
return ma_context_get_device_info(pDevice->pContext, type, &pDevice->playback.id, pDeviceInfo);
} else {
return ma_context_get_device_info(pDevice->pContext, type, &pDevice->capture.id, pDeviceInfo);
}
}
MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator)
{
ma_result result;
ma_device_info deviceInfo;
if (pLengthNotIncludingNullTerminator != NULL) {
*pLengthNotIncludingNullTerminator = 0;
}
if (pName != NULL && nameCap > 0) {
pName[0] = '\0';
}
result = ma_device_get_info(pDevice, type, &deviceInfo);
if (result != MA_SUCCESS) {
return result;
}
if (pName != NULL) {
ma_strncpy_s(pName, nameCap, deviceInfo.name, (size_t)-1);
/*
For safety, make sure the length is based on the truncated output string rather than the
source. Otherwise the caller might assume the output buffer contains more content than it
actually does.
*/
if (pLengthNotIncludingNullTerminator != NULL) {
*pLengthNotIncludingNullTerminator = strlen(pName);
}
} else {
/* Name not specified. Just report the length of the source string. */
if (pLengthNotIncludingNullTerminator != NULL) {
*pLengthNotIncludingNullTerminator = strlen(deviceInfo.name);
}
}
return MA_SUCCESS;
}
MA_API ma_result ma_device_start(ma_device* pDevice) MA_API ma_result ma_device_start(ma_device* pDevice)
{ {
ma_result result; ma_result result;
...@@ -35900,22 +36005,23 @@ MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma ...@@ -35900,22 +36005,23 @@ MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma
ma_spatializer_config config; ma_spatializer_config config;
MA_ZERO_OBJECT(&config); MA_ZERO_OBJECT(&config);
config.channelsIn = channelsIn; config.channelsIn = channelsIn;
config.channelsOut = channelsOut; config.channelsOut = channelsOut;
config.pChannelMapIn = NULL; config.pChannelMapIn = NULL;
config.attenuationModel = ma_attenuation_model_inverse; config.attenuationModel = ma_attenuation_model_inverse;
config.positioning = ma_positioning_absolute; config.positioning = ma_positioning_absolute;
config.handedness = ma_handedness_right; config.handedness = ma_handedness_right;
config.minGain = 0; config.minGain = 0;
config.maxGain = 1; config.maxGain = 1;
config.minDistance = 1; config.minDistance = 1;
config.maxDistance = MA_FLT_MAX; config.maxDistance = MA_FLT_MAX;
config.rolloff = 1; config.rolloff = 1;
config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */ config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */
config.coneOuterAngleInRadians = 6.283185f; /* 360 degress. */ config.coneOuterAngleInRadians = 6.283185f; /* 360 degress. */
config.coneOuterGain = 0.0f; config.coneOuterGain = 0.0f;
config.dopplerFactor = 1; config.dopplerFactor = 1;
config.gainSmoothTimeInFrames = 360; /* 7.5ms @ 48K. */ config.directionalAttenuationFactor = 1;
config.gainSmoothTimeInFrames = 360; /* 7.5ms @ 48K. */
return config; return config;
} }
...@@ -36227,64 +36333,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ...@@ -36227,64 +36333,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer,
sound's position and direction so that it's relative to listener. Later on we'll use sound's position and direction so that it's relative to listener. Later on we'll use
this for determining the factors to apply to each channel to apply the panning effect. this for determining the factors to apply to each channel to apply the panning effect.
*/ */
ma_vec3f v; ma_spatializer_get_relative_position_and_direction(pSpatializer, pListener, &relativePos, &relativeDir);
ma_vec3f axisX;
ma_vec3f axisY;
ma_vec3f axisZ;
float m[4][4];
/*
We need to calcualte the right vector from our forward and up vectors. This is done with
a cross product.
*/
axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */
axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */
/*
The calculation of axisX above can result in a zero-length vector if the listener is
looking straight up on the Y axis. We'll need to fall back to a +X in this case so that
the calculations below don't fall apart. This is where a quaternion based listener and
sound orientation would come in handy.
*/
if (ma_vec3f_len2(axisX) == 0) {
axisX = ma_vec3f_init_3f(1, 0, 0);
}
axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */
/*
We need to swap the X axis if we're left handed because otherwise the cross product above
will have resulted in it pointing in the wrong direction (right handed was assumed in the
cross products above).
*/
if (pListener->config.handedness == ma_handedness_left) {
axisX = ma_vec3f_neg(axisX);
}
/* Lookat. */
m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position);
m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position);
m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), pListener->position);
m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1;
/*
Multiply the lookat matrix by the spatializer position to transform it to listener
space. This allows calculations to work based on the sound being relative to the
origin which makes things simpler.
*/
v = pSpatializer->position;
relativePos.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1;
relativePos.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1;
relativePos.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1;
/*
The direction of the sound needs to also be transformed so that it's relative to the
rotation of the listener.
*/
v = pSpatializer->direction;
relativeDir.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z;
relativeDir.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z;
relativeDir.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z;
} }
distance = ma_vec3f_len(relativePos); distance = ma_vec3f_len(relativePos);
...@@ -36421,7 +36470,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ...@@ -36421,7 +36470,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer,
channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannel); channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannel);
if (ma_is_spatial_channel_position(channelOut)) { if (ma_is_spatial_channel_position(channelOut)) {
d = ma_vec3f_dot(unitPos, ma_get_channel_direction(channelOut)); d = ma_mix_f32_fast(1, ma_vec3f_dot(unitPos, ma_get_channel_direction(channelOut)), pSpatializer->config.directionalAttenuationFactor);
} else { } else {
d = 1; /* It's not a spatial channel so there's no real notion of direction. */ d = 1; /* It's not a spatial channel so there's no real notion of direction. */
} }
...@@ -36702,6 +36751,24 @@ MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatialize ...@@ -36702,6 +36751,24 @@ MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatialize
return pSpatializer->config.dopplerFactor; return pSpatializer->config.dopplerFactor;
} }
MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor)
{
if (pSpatializer == NULL) {
return;
}
pSpatializer->config.directionalAttenuationFactor = directionalAttenuationFactor;
}
MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer)
{
if (pSpatializer == NULL) {
return 1;
}
return pSpatializer->config.directionalAttenuationFactor;
}
MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z) MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z)
{ {
if (pSpatializer == NULL) { if (pSpatializer == NULL) {
...@@ -36756,6 +36823,98 @@ MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer) ...@@ -36756,6 +36823,98 @@ MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer)
return pSpatializer->velocity; return pSpatializer->velocity;
} }
MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir)
{
if (pRelativePos != NULL) {
pRelativePos->x = 0;
pRelativePos->y = 0;
pRelativePos->z = 0;
}
if (pRelativeDir != NULL) {
pRelativeDir->x = 0;
pRelativeDir->y = 0;
pRelativeDir->z = -1;
}
if (pSpatializer == NULL) {
return;
}
if (pListener == NULL || pSpatializer->config.positioning == ma_positioning_relative) {
/* There's no listener or we're using relative positioning. */
if (pRelativePos != NULL) {
*pRelativePos = pSpatializer->position;
}
if (pRelativeDir != NULL) {
*pRelativeDir = pSpatializer->direction;
}
} else {
ma_vec3f v;
ma_vec3f axisX;
ma_vec3f axisY;
ma_vec3f axisZ;
float m[4][4];
/*
We need to calcualte the right vector from our forward and up vectors. This is done with
a cross product.
*/
axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */
axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */
/*
The calculation of axisX above can result in a zero-length vector if the listener is
looking straight up on the Y axis. We'll need to fall back to a +X in this case so that
the calculations below don't fall apart. This is where a quaternion based listener and
sound orientation would come in handy.
*/
if (ma_vec3f_len2(axisX) == 0) {
axisX = ma_vec3f_init_3f(1, 0, 0);
}
axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */
/*
We need to swap the X axis if we're left handed because otherwise the cross product above
will have resulted in it pointing in the wrong direction (right handed was assumed in the
cross products above).
*/
if (pListener->config.handedness == ma_handedness_left) {
axisX = ma_vec3f_neg(axisX);
}
/* Lookat. */
m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position);
m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position);
m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), pListener->position);
m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1;
/*
Multiply the lookat matrix by the spatializer position to transform it to listener
space. This allows calculations to work based on the sound being relative to the
origin which makes things simpler.
*/
if (pRelativePos != NULL) {
v = pSpatializer->position;
pRelativePos->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1;
pRelativePos->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1;
pRelativePos->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1;
}
/*
The direction of the sound needs to also be transformed so that it's relative to the
rotation of the listener.
*/
if (pRelativeDir != NULL) {
v = pSpatializer->direction;
pRelativeDir->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z;
pRelativeDir->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z;
pRelativeDir->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z;
}
}
}
...@@ -45339,7 +45498,7 @@ extern "C" { ...@@ -45339,7 +45498,7 @@ extern "C" {
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12 #define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 32 #define DRFLAC_VERSION_REVISION 33
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> #include <stddef.h>
typedef signed char drflac_int8; typedef signed char drflac_int8;
...@@ -45365,7 +45524,7 @@ typedef unsigned int drflac_uint32; ...@@ -45365,7 +45524,7 @@ typedef unsigned int drflac_uint32;
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#endif #endif
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
typedef drflac_uint64 drflac_uintptr; typedef drflac_uint64 drflac_uintptr;
#else #else
typedef drflac_uint32 drflac_uintptr; typedef drflac_uint32 drflac_uintptr;
...@@ -52454,7 +52613,7 @@ static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_m ...@@ -52454,7 +52613,7 @@ static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_m
{ {
MA_ASSERT(pDataBufferNode != NULL); MA_ASSERT(pDataBufferNode != NULL);
return c89atomic_load_i32((ma_result*)&pDataBufferNode->result); /* Need a naughty const-cast here. */ return (ma_result)c89atomic_load_i32((ma_result*)&pDataBufferNode->result); /* Need a naughty const-cast here. */
} }
...@@ -52510,7 +52669,7 @@ static void ma_resource_manager_inline_notification_wait(ma_resource_manager_inl ...@@ -52510,7 +52669,7 @@ static void ma_resource_manager_inline_notification_wait(ma_resource_manager_inl
} else { } else {
while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) { while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) {
ma_result result = ma_resource_manager_process_next_job(pNotification->pResourceManager); ma_result result = ma_resource_manager_process_next_job(pNotification->pResourceManager);
if (result == MA_NO_DATA_AVAILABLE || result == MA_RESOURCE_MANAGER_JOB_QUIT) { if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) {
break; break;
} }
} }
...@@ -53590,7 +53749,7 @@ stage2: ...@@ -53590,7 +53749,7 @@ stage2:
if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) { if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) { while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) {
result = ma_resource_manager_process_next_job(pResourceManager); result = ma_resource_manager_process_next_job(pResourceManager);
if (result == MA_NO_DATA_AVAILABLE || result == MA_RESOURCE_MANAGER_JOB_QUIT) { if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) {
result = MA_SUCCESS; result = MA_SUCCESS;
break; break;
} }
...@@ -54147,7 +54306,7 @@ MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manage ...@@ -54147,7 +54306,7 @@ MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manage
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
return c89atomic_load_i32((ma_result*)&pDataBuffer->result); /* Need a naughty const-cast here. */ return (ma_result)c89atomic_load_i32((ma_result*)&pDataBuffer->result); /* Need a naughty const-cast here. */
} }
MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping) MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping)
...@@ -54964,7 +55123,7 @@ MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manage ...@@ -54964,7 +55123,7 @@ MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manage
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
return c89atomic_load_i32(&pDataStream->result); return (ma_result)c89atomic_load_i32(&pDataStream->result);
} }
MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping) MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping)
...@@ -56171,6 +56330,7 @@ MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 glo ...@@ -56171,6 +56330,7 @@ MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 glo
} }
#define MA_NODE_OUTPUT_BUS_FLAG_HAS_READ 0x01 /* Whether or not this bus ready to read more data. Only used on nodes with multiple output buses. */
static ma_result ma_node_output_bus_init(ma_node* pNode, ma_uint32 outputBusIndex, ma_uint32 channels, ma_node_output_bus* pOutputBus) static ma_result ma_node_output_bus_init(ma_node* pNode, ma_uint32 outputBusIndex, ma_uint32 channels, ma_node_output_bus* pOutputBus)
{ {
...@@ -57619,6 +57779,8 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde ...@@ -57619,6 +57779,8 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
*/ */
if (frameCountIn > 0 || (pNodeBase->vtable->flags & MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES) != 0) { if (frameCountIn > 0 || (pNodeBase->vtable->flags & MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES) != 0) {
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */ ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
} else {
frameCountOut = 0; /* No data was processed. */
} }
} }
...@@ -59536,10 +59698,12 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -59536,10 +59698,12 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
ma_spatializer_listener_config listenerConfig; ma_spatializer_listener_config listenerConfig;
ma_uint32 iListener; ma_uint32 iListener;
if (pEngine != NULL) { if (pEngine == NULL) {
MA_ZERO_OBJECT(pEngine); return MA_INVALID_ARGS;
} }
MA_ZERO_OBJECT(pEngine);
/* The config is allowed to be NULL in which case we use defaults for everything. */ /* The config is allowed to be NULL in which case we use defaults for everything. */
if (pConfig != NULL) { if (pConfig != NULL) {
engineConfig = *pConfig; engineConfig = *pConfig;
...@@ -59668,7 +59832,13 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ...@@ -59668,7 +59832,13 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
#if !defined(MA_NO_DEVICE_IO) #if !defined(MA_NO_DEVICE_IO)
{ {
if (pEngine->pDevice != NULL) { if (pEngine->pDevice != NULL) {
listenerConfig.pChannelMapOut = pEngine->pDevice->playback.channelMap; /*
Temporarily disabled. There is a subtle bug here where front-left and front-right
will be used by the device's channel map, but this is not what we want to use for
spatialization. Instead we want to use side-left and side-right. I need to figure
out a better solution for this. For now, disabling the user of device channel maps.
*/
/*listenerConfig.pChannelMapOut = pEngine->pDevice->playback.channelMap;*/
} }
} }
#endif #endif
...@@ -60765,6 +60935,42 @@ MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound) ...@@ -60765,6 +60935,42 @@ MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound)
return c89atomic_load_explicit_32(&pSound->engineNode.pinnedListenerIndex, c89atomic_memory_order_acquire); return c89atomic_load_explicit_32(&pSound->engineNode.pinnedListenerIndex, c89atomic_memory_order_acquire);
} }
MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound)
{
ma_uint32 listenerIndex;
if (pSound == NULL) {
return 0;
}
listenerIndex = ma_sound_get_pinned_listener_index(pSound);
if (listenerIndex == MA_LISTENER_INDEX_CLOSEST) {
ma_vec3f position = ma_sound_get_position(pSound);
return ma_engine_find_closest_listener(ma_sound_get_engine(pSound), position.x, position.y, position.z);
}
return listenerIndex;
}
MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound)
{
ma_vec3f relativePos;
ma_engine* pEngine;
if (pSound == NULL) {
return ma_vec3f_init_3f(0, 0, -1);
}
pEngine = ma_sound_get_engine(pSound);
if (pEngine == NULL) {
return ma_vec3f_init_3f(0, 0, -1);
}
ma_spatializer_get_relative_position_and_direction(&pSound->engineNode.spatializer, &pEngine->listeners[ma_sound_get_listener_index(pSound)], &relativePos, NULL);
return ma_vec3f_normalize(ma_vec3f_neg(relativePos));
}
MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z) MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z)
{ {
if (pSound == NULL) { if (pSound == NULL) {
...@@ -60989,6 +61195,24 @@ MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound) ...@@ -60989,6 +61195,24 @@ MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound)
return ma_spatializer_get_doppler_factor(&pSound->engineNode.spatializer); return ma_spatializer_get_doppler_factor(&pSound->engineNode.spatializer);
} }
MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor)
{
if (pSound == NULL) {
return;
}
ma_spatializer_set_directional_attenuation_factor(&pSound->engineNode.spatializer, directionalAttenuationFactor);
}
MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound)
{
if (pSound == NULL) {
return 1;
}
return ma_spatializer_get_directional_attenuation_factor(&pSound->engineNode.spatializer);
}
MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames) MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames)
{ {
...@@ -61328,6 +61552,16 @@ MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* ...@@ -61328,6 +61552,16 @@ MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group*
return ma_sound_get_pinned_listener_index(pGroup); return ma_sound_get_pinned_listener_index(pGroup);
} }
MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup)
{
return ma_sound_get_listener_index(pGroup);
}
MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup)
{
return ma_sound_get_direction_to_listener(pGroup);
}
MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z) MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z)
{ {
ma_sound_set_position(pGroup, x, y, z); ma_sound_set_position(pGroup, x, y, z);
...@@ -61448,6 +61682,16 @@ MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup) ...@@ -61448,6 +61682,16 @@ MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup)
return ma_sound_get_doppler_factor(pGroup); return ma_sound_get_doppler_factor(pGroup);
} }
MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor)
{
ma_sound_set_directional_attenuation_factor(pGroup, directionalAttenuationFactor);
}
MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup)
{
return ma_sound_get_directional_attenuation_factor(pGroup);
}
MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames) MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames)
{ {
ma_sound_set_fade_in_pcm_frames(pGroup, volumeBeg, volumeEnd, fadeLengthInFrames); ma_sound_set_fade_in_pcm_frames(pGroup, volumeBeg, volumeEnd, fadeLengthInFrames);
...@@ -70158,6 +70402,9 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac ...@@ -70158,6 +70402,9 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac
if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
return DRFLAC_FALSE; return DRFLAC_FALSE;
} }
if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) {
return DRFLAC_FALSE;
}
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
break; break;
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.0 - 2021-12-18 miniaudio - v0.11.1 - 2021-12-27
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -20,7 +20,7 @@ extern "C" { ...@@ -20,7 +20,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0 #define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 11 #define MA_VERSION_MINOR 11
#define MA_VERSION_REVISION 0 #define MA_VERSION_REVISION 1
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
...@@ -36,39 +36,9 @@ extern "C" { ...@@ -36,39 +36,9 @@ extern "C" {
#endif #endif
#endif #endif
/* Platform/backend detection. */
#ifdef _WIN32
#define MA_WIN32
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#define MA_WIN32_UWP
#else
#define MA_WIN32_DESKTOP
#endif
#else
#define MA_POSIX
#include <pthread.h> /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
#ifdef __unix__
#define MA_UNIX
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_BSD
#endif
#endif
#ifdef __linux__
#define MA_LINUX
#endif
#ifdef __APPLE__
#define MA_APPLE
#endif
#ifdef __ANDROID__
#define MA_ANDROID
#endif
#ifdef __EMSCRIPTEN__
#define MA_EMSCRIPTEN
#endif
#endif
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
#define MA_SIZEOF_PTR 8 #define MA_SIZEOF_PTR 8
#else #else
#define MA_SIZEOF_PTR 4 #define MA_SIZEOF_PTR 4
...@@ -131,6 +101,56 @@ typedef ma_uint16 wchar_t; ...@@ -131,6 +101,56 @@ typedef ma_uint16 wchar_t;
#endif #endif
/* Platform/backend detection. */
#ifdef _WIN32
#define MA_WIN32
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#define MA_WIN32_UWP
#else
#define MA_WIN32_DESKTOP
#endif
#else
#define MA_POSIX
/*
Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented.
You can use this to avoid including pthread.h in the header section. The downside is that it
results in some fixed sized structures being declared for the various types that are used in
miniaudio. The risk here is that these types might be too small for a given platform. This
risk is yours to take and no support will be offered if you enable this option.
*/
#ifndef MA_NO_PTHREAD_IN_HEADER
#include <pthread.h> /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
typedef pthread_t ma_pthread_t;
typedef pthread_mutex_t ma_pthread_mutex_t;
typedef pthread_cond_t ma_pthread_cond_t;
#else
typedef ma_uintptr ma_pthread_t;
typedef union ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t;
typedef union ma_pthread_cond_t { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t;
#endif
#ifdef __unix__
#define MA_UNIX
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_BSD
#endif
#endif
#ifdef __linux__
#define MA_LINUX
#endif
#ifdef __APPLE__
#define MA_APPLE
#endif
#ifdef __ANDROID__
#define MA_ANDROID
#endif
#ifdef __EMSCRIPTEN__
#define MA_EMSCRIPTEN
#endif
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define MA_INLINE __forceinline #define MA_INLINE __forceinline
#elif defined(__GNUC__) #elif defined(__GNUC__)
...@@ -247,148 +267,152 @@ typedef struct ma_context ma_context; ...@@ -247,148 +267,152 @@ typedef struct ma_context ma_context;
typedef struct ma_device ma_device; typedef struct ma_device ma_device;
typedef ma_uint8 ma_channel; typedef ma_uint8 ma_channel;
#define MA_CHANNEL_NONE 0 typedef enum
#define MA_CHANNEL_MONO 1 {
#define MA_CHANNEL_FRONT_LEFT 2 MA_CHANNEL_NONE = 0,
#define MA_CHANNEL_FRONT_RIGHT 3 MA_CHANNEL_MONO = 1,
#define MA_CHANNEL_FRONT_CENTER 4 MA_CHANNEL_FRONT_LEFT = 2,
#define MA_CHANNEL_LFE 5 MA_CHANNEL_FRONT_RIGHT = 3,
#define MA_CHANNEL_BACK_LEFT 6 MA_CHANNEL_FRONT_CENTER = 4,
#define MA_CHANNEL_BACK_RIGHT 7 MA_CHANNEL_LFE = 5,
#define MA_CHANNEL_FRONT_LEFT_CENTER 8 MA_CHANNEL_BACK_LEFT = 6,
#define MA_CHANNEL_FRONT_RIGHT_CENTER 9 MA_CHANNEL_BACK_RIGHT = 7,
#define MA_CHANNEL_BACK_CENTER 10 MA_CHANNEL_FRONT_LEFT_CENTER = 8,
#define MA_CHANNEL_SIDE_LEFT 11 MA_CHANNEL_FRONT_RIGHT_CENTER = 9,
#define MA_CHANNEL_SIDE_RIGHT 12 MA_CHANNEL_BACK_CENTER = 10,
#define MA_CHANNEL_TOP_CENTER 13 MA_CHANNEL_SIDE_LEFT = 11,
#define MA_CHANNEL_TOP_FRONT_LEFT 14 MA_CHANNEL_SIDE_RIGHT = 12,
#define MA_CHANNEL_TOP_FRONT_CENTER 15 MA_CHANNEL_TOP_CENTER = 13,
#define MA_CHANNEL_TOP_FRONT_RIGHT 16 MA_CHANNEL_TOP_FRONT_LEFT = 14,
#define MA_CHANNEL_TOP_BACK_LEFT 17 MA_CHANNEL_TOP_FRONT_CENTER = 15,
#define MA_CHANNEL_TOP_BACK_CENTER 18 MA_CHANNEL_TOP_FRONT_RIGHT = 16,
#define MA_CHANNEL_TOP_BACK_RIGHT 19 MA_CHANNEL_TOP_BACK_LEFT = 17,
#define MA_CHANNEL_AUX_0 20 MA_CHANNEL_TOP_BACK_CENTER = 18,
#define MA_CHANNEL_AUX_1 21 MA_CHANNEL_TOP_BACK_RIGHT = 19,
#define MA_CHANNEL_AUX_2 22 MA_CHANNEL_AUX_0 = 20,
#define MA_CHANNEL_AUX_3 23 MA_CHANNEL_AUX_1 = 21,
#define MA_CHANNEL_AUX_4 24 MA_CHANNEL_AUX_2 = 22,
#define MA_CHANNEL_AUX_5 25 MA_CHANNEL_AUX_3 = 23,
#define MA_CHANNEL_AUX_6 26 MA_CHANNEL_AUX_4 = 24,
#define MA_CHANNEL_AUX_7 27 MA_CHANNEL_AUX_5 = 25,
#define MA_CHANNEL_AUX_8 28 MA_CHANNEL_AUX_6 = 26,
#define MA_CHANNEL_AUX_9 29 MA_CHANNEL_AUX_7 = 27,
#define MA_CHANNEL_AUX_10 30 MA_CHANNEL_AUX_8 = 28,
#define MA_CHANNEL_AUX_11 31 MA_CHANNEL_AUX_9 = 29,
#define MA_CHANNEL_AUX_12 32 MA_CHANNEL_AUX_10 = 30,
#define MA_CHANNEL_AUX_13 33 MA_CHANNEL_AUX_11 = 31,
#define MA_CHANNEL_AUX_14 34 MA_CHANNEL_AUX_12 = 32,
#define MA_CHANNEL_AUX_15 35 MA_CHANNEL_AUX_13 = 33,
#define MA_CHANNEL_AUX_16 36 MA_CHANNEL_AUX_14 = 34,
#define MA_CHANNEL_AUX_17 37 MA_CHANNEL_AUX_15 = 35,
#define MA_CHANNEL_AUX_18 38 MA_CHANNEL_AUX_16 = 36,
#define MA_CHANNEL_AUX_19 39 MA_CHANNEL_AUX_17 = 37,
#define MA_CHANNEL_AUX_20 40 MA_CHANNEL_AUX_18 = 38,
#define MA_CHANNEL_AUX_21 41 MA_CHANNEL_AUX_19 = 39,
#define MA_CHANNEL_AUX_22 42 MA_CHANNEL_AUX_20 = 40,
#define MA_CHANNEL_AUX_23 43 MA_CHANNEL_AUX_21 = 41,
#define MA_CHANNEL_AUX_24 44 MA_CHANNEL_AUX_22 = 42,
#define MA_CHANNEL_AUX_25 45 MA_CHANNEL_AUX_23 = 43,
#define MA_CHANNEL_AUX_26 46 MA_CHANNEL_AUX_24 = 44,
#define MA_CHANNEL_AUX_27 47 MA_CHANNEL_AUX_25 = 45,
#define MA_CHANNEL_AUX_28 48 MA_CHANNEL_AUX_26 = 46,
#define MA_CHANNEL_AUX_29 49 MA_CHANNEL_AUX_27 = 47,
#define MA_CHANNEL_AUX_30 50 MA_CHANNEL_AUX_28 = 48,
#define MA_CHANNEL_AUX_31 51 MA_CHANNEL_AUX_29 = 49,
#define MA_CHANNEL_LEFT MA_CHANNEL_FRONT_LEFT MA_CHANNEL_AUX_30 = 50,
#define MA_CHANNEL_RIGHT MA_CHANNEL_FRONT_RIGHT MA_CHANNEL_AUX_31 = 51,
#define MA_CHANNEL_POSITION_COUNT (MA_CHANNEL_AUX_31 + 1) MA_CHANNEL_LEFT = MA_CHANNEL_FRONT_LEFT,
MA_CHANNEL_RIGHT = MA_CHANNEL_FRONT_RIGHT,
MA_CHANNEL_POSITION_COUNT = (MA_CHANNEL_AUX_31 + 1)
typedef int ma_result; } _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */
#define MA_SUCCESS 0
#define MA_ERROR -1 /* A generic error. */ typedef enum
#define MA_INVALID_ARGS -2 {
#define MA_INVALID_OPERATION -3 MA_SUCCESS = 0,
#define MA_OUT_OF_MEMORY -4 MA_ERROR = -1, /* A generic error. */
#define MA_OUT_OF_RANGE -5 MA_INVALID_ARGS = -2,
#define MA_ACCESS_DENIED -6 MA_INVALID_OPERATION = -3,
#define MA_DOES_NOT_EXIST -7 MA_OUT_OF_MEMORY = -4,
#define MA_ALREADY_EXISTS -8 MA_OUT_OF_RANGE = -5,
#define MA_TOO_MANY_OPEN_FILES -9 MA_ACCESS_DENIED = -6,
#define MA_INVALID_FILE -10 MA_DOES_NOT_EXIST = -7,
#define MA_TOO_BIG -11 MA_ALREADY_EXISTS = -8,
#define MA_PATH_TOO_LONG -12 MA_TOO_MANY_OPEN_FILES = -9,
#define MA_NAME_TOO_LONG -13 MA_INVALID_FILE = -10,
#define MA_NOT_DIRECTORY -14 MA_TOO_BIG = -11,
#define MA_IS_DIRECTORY -15 MA_PATH_TOO_LONG = -12,
#define MA_DIRECTORY_NOT_EMPTY -16 MA_NAME_TOO_LONG = -13,
#define MA_AT_END -17 MA_NOT_DIRECTORY = -14,
#define MA_NO_SPACE -18 MA_IS_DIRECTORY = -15,
#define MA_BUSY -19 MA_DIRECTORY_NOT_EMPTY = -16,
#define MA_IO_ERROR -20 MA_AT_END = -17,
#define MA_INTERRUPT -21 MA_NO_SPACE = -18,
#define MA_UNAVAILABLE -22 MA_BUSY = -19,
#define MA_ALREADY_IN_USE -23 MA_IO_ERROR = -20,
#define MA_BAD_ADDRESS -24 MA_INTERRUPT = -21,
#define MA_BAD_SEEK -25 MA_UNAVAILABLE = -22,
#define MA_BAD_PIPE -26 MA_ALREADY_IN_USE = -23,
#define MA_DEADLOCK -27 MA_BAD_ADDRESS = -24,
#define MA_TOO_MANY_LINKS -28 MA_BAD_SEEK = -25,
#define MA_NOT_IMPLEMENTED -29 MA_BAD_PIPE = -26,
#define MA_NO_MESSAGE -30 MA_DEADLOCK = -27,
#define MA_BAD_MESSAGE -31 MA_TOO_MANY_LINKS = -28,
#define MA_NO_DATA_AVAILABLE -32 MA_NOT_IMPLEMENTED = -29,
#define MA_INVALID_DATA -33 MA_NO_MESSAGE = -30,
#define MA_TIMEOUT -34 MA_BAD_MESSAGE = -31,
#define MA_NO_NETWORK -35 MA_NO_DATA_AVAILABLE = -32,
#define MA_NOT_UNIQUE -36 MA_INVALID_DATA = -33,
#define MA_NOT_SOCKET -37 MA_TIMEOUT = -34,
#define MA_NO_ADDRESS -38 MA_NO_NETWORK = -35,
#define MA_BAD_PROTOCOL -39 MA_NOT_UNIQUE = -36,
#define MA_PROTOCOL_UNAVAILABLE -40 MA_NOT_SOCKET = -37,
#define MA_PROTOCOL_NOT_SUPPORTED -41 MA_NO_ADDRESS = -38,
#define MA_PROTOCOL_FAMILY_NOT_SUPPORTED -42 MA_BAD_PROTOCOL = -39,
#define MA_ADDRESS_FAMILY_NOT_SUPPORTED -43 MA_PROTOCOL_UNAVAILABLE = -40,
#define MA_SOCKET_NOT_SUPPORTED -44 MA_PROTOCOL_NOT_SUPPORTED = -41,
#define MA_CONNECTION_RESET -45 MA_PROTOCOL_FAMILY_NOT_SUPPORTED = -42,
#define MA_ALREADY_CONNECTED -46 MA_ADDRESS_FAMILY_NOT_SUPPORTED = -43,
#define MA_NOT_CONNECTED -47 MA_SOCKET_NOT_SUPPORTED = -44,
#define MA_CONNECTION_REFUSED -48 MA_CONNECTION_RESET = -45,
#define MA_NO_HOST -49 MA_ALREADY_CONNECTED = -46,
#define MA_IN_PROGRESS -50 MA_NOT_CONNECTED = -47,
#define MA_CANCELLED -51 MA_CONNECTION_REFUSED = -48,
#define MA_MEMORY_ALREADY_MAPPED -52 MA_NO_HOST = -49,
MA_IN_PROGRESS = -50,
/* General miniaudio-specific errors. */ MA_CANCELLED = -51,
#define MA_FORMAT_NOT_SUPPORTED -100 MA_MEMORY_ALREADY_MAPPED = -52,
#define MA_DEVICE_TYPE_NOT_SUPPORTED -101
#define MA_SHARE_MODE_NOT_SUPPORTED -102 /* General miniaudio-specific errors. */
#define MA_NO_BACKEND -103 MA_FORMAT_NOT_SUPPORTED = -100,
#define MA_NO_DEVICE -104 MA_DEVICE_TYPE_NOT_SUPPORTED = -101,
#define MA_API_NOT_FOUND -105 MA_SHARE_MODE_NOT_SUPPORTED = -102,
#define MA_INVALID_DEVICE_CONFIG -106 MA_NO_BACKEND = -103,
#define MA_LOOP -107 MA_NO_DEVICE = -104,
MA_API_NOT_FOUND = -105,
/* State errors. */ MA_INVALID_DEVICE_CONFIG = -106,
#define MA_DEVICE_NOT_INITIALIZED -200 MA_LOOP = -107,
#define MA_DEVICE_ALREADY_INITIALIZED -201
#define MA_DEVICE_NOT_STARTED -202 /* State errors. */
#define MA_DEVICE_NOT_STOPPED -203 MA_DEVICE_NOT_INITIALIZED = -200,
MA_DEVICE_ALREADY_INITIALIZED = -201,
/* Operation errors. */ MA_DEVICE_NOT_STARTED = -202,
#define MA_FAILED_TO_INIT_BACKEND -300 MA_DEVICE_NOT_STOPPED = -203,
#define MA_FAILED_TO_OPEN_BACKEND_DEVICE -301
#define MA_FAILED_TO_START_BACKEND_DEVICE -302 /* Operation errors. */
#define MA_FAILED_TO_STOP_BACKEND_DEVICE -303 MA_FAILED_TO_INIT_BACKEND = -300,
MA_FAILED_TO_OPEN_BACKEND_DEVICE = -301,
MA_FAILED_TO_START_BACKEND_DEVICE = -302,
#define MA_MIN_CHANNELS 1 MA_FAILED_TO_STOP_BACKEND_DEVICE = -303
#ifndef MA_MAX_CHANNELS } ma_result;
#define MA_MAX_CHANNELS 254
#define MA_MIN_CHANNELS 1
#ifndef MA_MAX_CHANNELS
#define MA_MAX_CHANNELS 254
#endif #endif
#ifndef MA_MAX_FILTER_ORDER #ifndef MA_MAX_FILTER_ORDER
#define MA_MAX_FILTER_ORDER 8 #define MA_MAX_FILTER_ORDER 8
#endif #endif
typedef enum typedef enum
...@@ -515,14 +539,14 @@ typedef enum ...@@ -515,14 +539,14 @@ typedef enum
typedef ma_handle ma_thread; typedef ma_handle ma_thread;
#endif #endif
#if defined(MA_POSIX) #if defined(MA_POSIX)
typedef pthread_t ma_thread; typedef ma_pthread_t ma_thread;
#endif #endif
#if defined(MA_WIN32) #if defined(MA_WIN32)
typedef ma_handle ma_mutex; typedef ma_handle ma_mutex;
#endif #endif
#if defined(MA_POSIX) #if defined(MA_POSIX)
typedef pthread_mutex_t ma_mutex; typedef ma_pthread_mutex_t ma_mutex;
#endif #endif
#if defined(MA_WIN32) #if defined(MA_WIN32)
...@@ -532,8 +556,8 @@ typedef ma_handle ma_event; ...@@ -532,8 +556,8 @@ typedef ma_handle ma_event;
typedef struct typedef struct
{ {
ma_uint32 value; ma_uint32 value;
pthread_mutex_t lock; ma_pthread_mutex_t lock;
pthread_cond_t cond; ma_pthread_cond_t cond;
} ma_event; } ma_event;
#endif /* MA_POSIX */ #endif /* MA_POSIX */
...@@ -544,8 +568,8 @@ typedef ma_handle ma_semaphore; ...@@ -544,8 +568,8 @@ typedef ma_handle ma_semaphore;
typedef struct typedef struct
{ {
int value; int value;
pthread_mutex_t lock; ma_pthread_mutex_t lock;
pthread_cond_t cond; ma_pthread_cond_t cond;
} ma_semaphore; } ma_semaphore;
#endif /* MA_POSIX */ #endif /* MA_POSIX */
#else #else
...@@ -1280,7 +1304,8 @@ typedef struct ...@@ -1280,7 +1304,8 @@ typedef struct
float coneInnerAngleInRadians; float coneInnerAngleInRadians;
float coneOuterAngleInRadians; float coneOuterAngleInRadians;
float coneOuterGain; float coneOuterGain;
float dopplerFactor; /* Set to 0 to disable doppler effect. This will run on a fast path. */ float dopplerFactor; /* Set to 0 to disable doppler effect. */
float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */
ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */ ma_uint32 gainSmoothTimeInFrames; /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */
} ma_spatializer_config; } ma_spatializer_config;
...@@ -1327,12 +1352,15 @@ MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAng ...@@ -1327,12 +1352,15 @@ MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAng
MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor); MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor);
MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer); MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer);
MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor);
MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer);
MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z); MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z);
MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer); MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer);
MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z); MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z);
MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer); MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer);
MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z); MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z);
MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer); MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer);
MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir);
...@@ -2320,11 +2348,15 @@ typedef struct ma_backend_callbacks ma_backend_callbacks; ...@@ -2320,11 +2348,15 @@ typedef struct ma_backend_callbacks ma_backend_callbacks;
#define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */ #define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
#ifndef MA_MAX_DEVICE_NAME_LENGTH
#define MA_MAX_DEVICE_NAME_LENGTH 255
#endif
typedef struct typedef struct
{ {
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */ /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
ma_device_id id; ma_device_id id;
char name[256]; char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* +1 for null terminator. */
ma_bool32 isDefault; ma_bool32 isDefault;
ma_uint32 nativeDataFormatCount; ma_uint32 nativeDataFormatCount;
...@@ -2469,7 +2501,7 @@ callbacks defined in this structure. ...@@ -2469,7 +2501,7 @@ callbacks defined in this structure.
Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
needs to stop and the `onContextEnumerateDevices()` function return with a success code. needs to stop and the `onContextEnumerateDevices()` function returns with a success code.
Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID, Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
...@@ -2511,6 +2543,9 @@ callback. When the device is stopped, the `ma_device_get_state() == ma_device_st ...@@ -2511,6 +2543,9 @@ callback. When the device is stopped, the `ma_device_get_state() == ma_device_st
which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback, which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
wake up the audio thread. wake up the audio thread.
If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the
`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient.
*/ */
struct ma_backend_callbacks struct ma_backend_callbacks
{ {
...@@ -2526,6 +2561,7 @@ struct ma_backend_callbacks ...@@ -2526,6 +2561,7 @@ struct ma_backend_callbacks
ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten); ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten);
ma_result (* onDeviceDataLoop)(ma_device* pDevice); ma_result (* onDeviceDataLoop)(ma_device* pDevice);
ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice); ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice);
ma_result (* onDeviceGetInfo)(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo);
}; };
struct ma_context_config struct ma_context_config
...@@ -3029,7 +3065,7 @@ struct ma_device ...@@ -3029,7 +3065,7 @@ struct ma_device
struct struct
{ {
ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */
ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
ma_format format; ma_format format;
ma_uint32 channels; ma_uint32 channels;
...@@ -3050,7 +3086,7 @@ struct ma_device ...@@ -3050,7 +3086,7 @@ struct ma_device
struct struct
{ {
ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */ ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */ char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* Maybe temporary. Likely to be replaced with a query API. */
ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
ma_format format; ma_format format;
ma_uint32 channels; ma_uint32 channels;
...@@ -4216,6 +4252,95 @@ Helper function for retrieving the log object associated with the context that o ...@@ -4216,6 +4252,95 @@ Helper function for retrieving the log object associated with the context that o
MA_API ma_log* ma_device_get_log(ma_device* pDevice); MA_API ma_log* ma_device_get_log(ma_device* pDevice);
/*
Retrieves information about the device.
Parameters
----------
pDevice (in)
A pointer to the device whose information is being retrieved.
type (in)
The device type. This parameter is required for duplex devices. When retrieving device
information, you are doing so for an individual playback or capture device.
pDeviceInfo (out)
A pointer to the `ma_device_info` that will receive the device information.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. This should be considered unsafe because it may be calling into the backend which may or
may not be safe.
Callback Safety
---------------
Unsafe. You should avoid calling this in the data callback because it may call into the backend
which may or may not be safe.
*/
MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo);
/*
Retrieves the name of the device.
Parameters
----------
pDevice (in)
A pointer to the device whose information is being retrieved.
type (in)
The device type. This parameter is required for duplex devices. When retrieving device
information, you are doing so for an individual playback or capture device.
pName (out)
A pointer to the buffer that will receive the name.
nameCap (in)
The capacity of the output buffer, including space for the null terminator.
pLengthNotIncludingNullTerminator (out, optional)
A pointer to the variable that will receive the length of the name, not including the null
terminator.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. This should be considered unsafe because it may be calling into the backend which may or
may not be safe.
Callback Safety
---------------
Unsafe. You should avoid calling this in the data callback because it may call into the backend
which may or may not be safe.
Remarks
-------
If the name does not fully fit into the output buffer, it'll be truncated. You can pass in NULL to
`pName` if you want to first get the length of the name for the purpose of memory allocation of the
output buffer. Allocating a buffer of size `MA_MAX_DEVICE_NAME_LENGTH + 1` should be enough for
most cases and will avoid the need for the inefficiency of calling this function twice.
This is implemented in terms of `ma_device_get_info()`.
*/
MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator);
/* /*
Starts the device. For playback devices this begins playback. For capture devices it begins recording. Starts the device. For playback devices this begins playback. For capture devices it begins recording.
...@@ -5269,8 +5394,11 @@ appropriate for a given situation. ...@@ -5269,8 +5394,11 @@ appropriate for a given situation.
typedef void ma_vfs; typedef void ma_vfs;
typedef ma_handle ma_vfs_file; typedef ma_handle ma_vfs_file;
#define MA_OPEN_MODE_READ 0x00000001 typedef enum
#define MA_OPEN_MODE_WRITE 0x00000002 {
MA_OPEN_MODE_READ = 0x00000001,
MA_OPEN_MODE_WRITE = 0x00000002
} ma_open_mode_flags;
typedef enum typedef enum
{ {
...@@ -5666,22 +5794,28 @@ typedef struct ma_resource_manager_data_buffer ma_resource_manager_data_buf ...@@ -5666,22 +5794,28 @@ typedef struct ma_resource_manager_data_buffer ma_resource_manager_data_buf
typedef struct ma_resource_manager_data_stream ma_resource_manager_data_stream; typedef struct ma_resource_manager_data_stream ma_resource_manager_data_stream;
typedef struct ma_resource_manager_data_source ma_resource_manager_data_source; typedef struct ma_resource_manager_data_source ma_resource_manager_data_source;
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM 0x00000001 /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */ typedef enum
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE 0x00000002 /* 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_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC 0x00000004 /* When set, the resource manager will load the data source asynchronously. */ MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM = 0x00000001, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT 0x00000008 /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */ MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE = 0x00000002, /* 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. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT = 0x00000008 /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
} ma_resource_manager_data_source_flags;
#define MA_RESOURCE_MANAGER_JOB_QUIT 0x00000000 typedef enum
#define MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE 0x00000001 {
#define MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE 0x00000002 MA_RESOURCE_MANAGER_JOB_QUIT = 0x00000000,
#define MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE 0x00000003 MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE = 0x00000001,
#define MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER 0x00000004 MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE = 0x00000002,
#define MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER 0x00000005 MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE = 0x00000003,
#define MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM 0x00000006 MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER = 0x00000004,
#define MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM 0x00000007 MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER = 0x00000005,
#define MA_RESOURCE_MANAGER_JOB_PAGE_DATA_STREAM 0x00000008 MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM = 0x00000006,
#define MA_RESOURCE_MANAGER_JOB_SEEK_DATA_STREAM 0x00000009 MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM = 0x00000007,
#define MA_RESOURCE_MANAGER_JOB_CUSTOM 0x00000100 /* Number your custom job codes as (MA_RESOURCE_MANAGER_JOB_CUSTOM + 0), (MA_RESOURCE_MANAGER_JOB_CUSTOM + 1), etc. */ MA_RESOURCE_MANAGER_JOB_PAGE_DATA_STREAM = 0x00000008,
MA_RESOURCE_MANAGER_JOB_SEEK_DATA_STREAM = 0x00000009,
MA_RESOURCE_MANAGER_JOB_CUSTOM = 0x00000100 /* Number your custom job codes as (MA_RESOURCE_MANAGER_JOB_CUSTOM + 0), (MA_RESOURCE_MANAGER_JOB_CUSTOM + 1), etc. */
} ma_resource_manager_job_type;
/* /*
...@@ -5804,7 +5938,10 @@ ma_resource_manager_job_queue_post(). ma_resource_manager_job_queue_next() will ...@@ -5804,7 +5938,10 @@ ma_resource_manager_job_queue_post(). ma_resource_manager_job_queue_next() will
This flag should always be used for platforms that do not support multithreading. This flag should always be used for platforms that do not support multithreading.
*/ */
#define MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING 0x00000001 typedef enum
{
MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING = 0x00000001
} ma_resource_manager_job_queue_flags;
typedef struct typedef struct
{ {
...@@ -5848,12 +5985,14 @@ MA_API ma_result ma_resource_manager_job_queue_next(ma_resource_manager_job_queu ...@@ -5848,12 +5985,14 @@ MA_API ma_result ma_resource_manager_job_queue_next(ma_resource_manager_job_queu
#define MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT 64 #define MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT 64
#endif #endif
/* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */ typedef enum
#define MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING 0x00000001 {
/* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
/* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */ MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING = 0x00000001,
#define MA_RESOURCE_MANAGER_FLAG_NO_THREADING 0x00000002
/* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */
MA_RESOURCE_MANAGER_FLAG_NO_THREADING = 0x00000002
} ma_resource_manager_flags;
typedef struct typedef struct
{ {
...@@ -6113,10 +6252,13 @@ typedef void ma_node; ...@@ -6113,10 +6252,13 @@ typedef void ma_node;
/* Node flags. */ /* Node flags. */
#define MA_NODE_FLAG_PASSTHROUGH 0x00000001 typedef enum
#define MA_NODE_FLAG_CONTINUOUS_PROCESSING 0x00000002 {
#define MA_NODE_FLAG_ALLOW_NULL_INPUT 0x00000004 MA_NODE_FLAG_PASSTHROUGH = 0x00000001,
#define MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES 0x00000008 MA_NODE_FLAG_CONTINUOUS_PROCESSING = 0x00000002,
MA_NODE_FLAG_ALLOW_NULL_INPUT = 0x00000004,
MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES = 0x00000008
} ma_node_flags;
/* The playback state of a node. Either started or stopped. */ /* The playback state of a node. Either started or stopped. */
...@@ -6132,7 +6274,7 @@ typedef struct ...@@ -6132,7 +6274,7 @@ typedef struct
/* /*
Extended processing callback. This callback is used for effects that process input and output Extended processing callback. This callback is used for effects that process input and output
at different rates (i.e. they perform resampling). This is similar to the simple version, only at different rates (i.e. they perform resampling). This is similar to the simple version, only
they take two sepate frame counts: one for input, and one for output. they take two seperate frame counts: one for input, and one for output.
On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas
`pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`. `pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`.
...@@ -6187,8 +6329,6 @@ MA_API ma_node_config ma_node_config_init(void); ...@@ -6187,8 +6329,6 @@ MA_API ma_node_config ma_node_config_init(void);
A node has multiple output buses. An output bus is attached to an input bus as an item in a linked A node has multiple output buses. An output bus is attached to an input bus as an item in a linked
list. Think of the input bus as a linked list, with the output bus being an item in that list. list. Think of the input bus as a linked list, with the output bus being an item in that list.
*/ */
#define MA_NODE_OUTPUT_BUS_FLAG_HAS_READ 0x01 /* Whether or not this bus ready to read more data. Only used on nodes with multiple output buses. */
typedef struct ma_node_output_bus ma_node_output_bus; typedef struct ma_node_output_bus ma_node_output_bus;
struct ma_node_output_bus struct ma_node_output_bus
{ {
...@@ -6199,7 +6339,7 @@ struct ma_node_output_bus ...@@ -6199,7 +6339,7 @@ struct ma_node_output_bus
/* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */ /* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */
MA_ATOMIC(1, ma_uint8) inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. */ MA_ATOMIC(1, ma_uint8) inputNodeInputBusIndex; /* The index of the input bus on the input. Required for detaching. */
MA_ATOMIC(4, ma_uint32) flags; /* Some state flags for tracking the read state of the output buffer. */ MA_ATOMIC(4, ma_uint32) flags; /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */
MA_ATOMIC(4, ma_uint32) refCount; /* Reference count for some thread-safety when detaching. */ MA_ATOMIC(4, ma_uint32) refCount; /* Reference count for some thread-safety when detaching. */
MA_ATOMIC(4, ma_bool32) isAttached; /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */ MA_ATOMIC(4, ma_bool32) isAttached; /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */
MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */ MA_ATOMIC(4, ma_spinlock) lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
...@@ -6569,13 +6709,16 @@ typedef struct ma_sound ma_sound; ...@@ -6569,13 +6709,16 @@ typedef struct ma_sound ma_sound;
/* Sound flags. */ /* Sound flags. */
#define MA_SOUND_FLAG_STREAM MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM /* 0x00000001 */ typedef enum
#define MA_SOUND_FLAG_DECODE MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE /* 0x00000002 */ {
#define MA_SOUND_FLAG_ASYNC MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC /* 0x00000004 */ MA_SOUND_FLAG_STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */
#define MA_SOUND_FLAG_WAIT_INIT MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT /* 0x00000008 */ MA_SOUND_FLAG_DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */
#define MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT 0x00000010 /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */ MA_SOUND_FLAG_ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */
#define MA_SOUND_FLAG_NO_PITCH 0x00000020 /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */ MA_SOUND_FLAG_WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */
#define MA_SOUND_FLAG_NO_SPATIALIZATION 0x00000040 /* Disable spatialization. */ MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT = 0x00000010, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */
MA_SOUND_FLAG_NO_PITCH = 0x00000020, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */
MA_SOUND_FLAG_NO_SPATIALIZATION = 0x00000040 /* Disable spatialization. */
} ma_sound_flags;
#ifndef MA_ENGINE_MAX_LISTENERS #ifndef MA_ENGINE_MAX_LISTENERS
#define MA_ENGINE_MAX_LISTENERS 4 #define MA_ENGINE_MAX_LISTENERS 4
...@@ -6802,6 +6945,8 @@ MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enab ...@@ -6802,6 +6945,8 @@ MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enab
MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound); MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound);
MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex); MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex);
MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound); MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound);
MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound);
MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound);
MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z); MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z);
MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound); MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound);
MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z); MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z);
...@@ -6826,6 +6971,8 @@ MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float ...@@ -6826,6 +6971,8 @@ MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float
MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor); MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor);
MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound); MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound);
MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor);
MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound);
MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames);
MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds);
MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound); MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound);
...@@ -6861,6 +7008,8 @@ MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma ...@@ -6861,6 +7008,8 @@ MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma
MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup); MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup);
MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex); MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex);
MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup); MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup);
MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup);
MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup);
MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z); MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z);
MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup); MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup);
MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z); MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z);
...@@ -6885,6 +7034,8 @@ MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRa ...@@ -6885,6 +7034,8 @@ MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRa
MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor); MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor);
MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup); MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup);
MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor);
MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup);
MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames); MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames);
MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds); MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds);
MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup); MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup);
......
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.1 - TBD miniaudio - v0.11.1 - 2021-12-27
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -3627,7 +3627,7 @@ extern "C" { ...@@ -3627,7 +3627,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0 #define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 11 #define MA_VERSION_MINOR 11
#define MA_VERSION_REVISION 0 #define MA_VERSION_REVISION 1
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
...@@ -56157,7 +56157,7 @@ extern "C" { ...@@ -56157,7 +56157,7 @@ extern "C" {
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12 #define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 32 #define DRFLAC_VERSION_REVISION 33
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> #include <stddef.h>
typedef signed char drflac_int8; typedef signed char drflac_int8;
...@@ -56183,7 +56183,7 @@ typedef unsigned int drflac_uint32; ...@@ -56183,7 +56183,7 @@ typedef unsigned int drflac_uint32;
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#endif #endif
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
typedef drflac_uint64 drflac_uintptr; typedef drflac_uint64 drflac_uintptr;
#else #else
typedef drflac_uint32 drflac_uintptr; typedef drflac_uint32 drflac_uintptr;
...@@ -81061,6 +81061,9 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac ...@@ -81061,6 +81061,9 @@ static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac
if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
return DRFLAC_FALSE; return DRFLAC_FALSE;
} }
if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) {
return DRFLAC_FALSE;
}
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
break; break;
...@@ -89123,7 +89126,7 @@ There have also been some other smaller changes added to this release. ...@@ -89123,7 +89126,7 @@ There have also been some other smaller changes added to this release.
/* /*
REVISION HISTORY REVISION HISTORY
================ ================
v0.11.1 - TBD v0.11.1 - 2021-12-27
- Result codes are now declared as an enum rather than #defines. - Result codes are now declared as an enum rather than #defines.
- Channel positions (MA_CHANNEL_*) are now declared as an enum rather than #defines. - Channel positions (MA_CHANNEL_*) are now declared as an enum rather than #defines.
- Add ma_device_get_info() for retrieving device information from an initialized device. - Add ma_device_get_info() for retrieving device information from an initialized device.
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