mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
Version 0.11.1
This commit is contained in:
+402
-155
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
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
|
||||
|
||||
@@ -34,6 +34,7 @@ GitHub: https://github.com/mackron/miniaudio
|
||||
#include <string.h> /* For memset() */
|
||||
#include <sched.h>
|
||||
#include <sys/time.h> /* select() (used for ma_sleep()). */
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h> /* For fstat(), etc. */
|
||||
@@ -4536,7 +4537,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority
|
||||
(void)stackSize;
|
||||
#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. */
|
||||
if (pAttr != NULL) {
|
||||
@@ -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)
|
||||
{
|
||||
pthread_join(*pThread, NULL);
|
||||
pthread_detach(*pThread);
|
||||
pthread_join((pthread_t)*pThread, NULL);
|
||||
pthread_detach((pthread_t)*pThread);
|
||||
}
|
||||
|
||||
|
||||
@@ -4587,14 +4588,14 @@ static ma_result ma_event_init__posix(ma_event* pEvent)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = pthread_mutex_init(&pEvent->lock, NULL);
|
||||
result = pthread_mutex_init((pthread_mutex_t*)&pEvent->lock, NULL);
|
||||
if (result != 0) {
|
||||
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) {
|
||||
pthread_mutex_destroy(&pEvent->lock);
|
||||
pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
|
||||
return ma_result_from_errno(result);
|
||||
}
|
||||
|
||||
@@ -4604,32 +4605,32 @@ static ma_result ma_event_init__posix(ma_event* pEvent)
|
||||
|
||||
static void ma_event_uninit__posix(ma_event* pEvent)
|
||||
{
|
||||
pthread_cond_destroy(&pEvent->cond);
|
||||
pthread_mutex_destroy(&pEvent->lock);
|
||||
pthread_cond_destroy((pthread_cond_t*)&pEvent->cond);
|
||||
pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
|
||||
}
|
||||
|
||||
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) {
|
||||
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. */
|
||||
}
|
||||
pthread_mutex_unlock(&pEvent->lock);
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
@@ -4645,14 +4646,14 @@ static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemap
|
||||
|
||||
pSemaphore->value = initialValue;
|
||||
|
||||
result = pthread_mutex_init(&pSemaphore->lock, NULL);
|
||||
result = pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock, NULL);
|
||||
if (result != 0) {
|
||||
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) {
|
||||
pthread_mutex_destroy(&pSemaphore->lock);
|
||||
pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
|
||||
return ma_result_from_errno(result); /* Failed to create condition variable. */
|
||||
}
|
||||
|
||||
@@ -4665,8 +4666,8 @@ static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_cond_destroy(&pSemaphore->cond);
|
||||
pthread_mutex_destroy(&pSemaphore->lock);
|
||||
pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond);
|
||||
pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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. */
|
||||
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;
|
||||
}
|
||||
pthread_mutex_unlock(&pSemaphore->lock);
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
@@ -4695,12 +4696,12 @@ static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&pSemaphore->lock);
|
||||
pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -4745,7 +4746,7 @@ static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priorit
|
||||
ma_thread_proxy_data* pProxyData;
|
||||
|
||||
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. */
|
||||
@@ -24370,8 +24371,9 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf
|
||||
ma_result result;
|
||||
ma_AAudioStreamBuilder* pBuilder;
|
||||
|
||||
MA_ASSERT(pConfig != NULL);
|
||||
MA_ASSERT(pConfig->deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */
|
||||
MA_ASSERT(pDevice != NULL);
|
||||
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;
|
||||
|
||||
@@ -24586,12 +24588,6 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf
|
||||
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) {
|
||||
result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture);
|
||||
if (result != MA_SUCCESS) {
|
||||
@@ -24731,6 +24727,36 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice)
|
||||
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)
|
||||
{
|
||||
@@ -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->onDeviceWrite = 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;
|
||||
return MA_SUCCESS;
|
||||
@@ -25132,6 +25159,7 @@ return_default_device:;
|
||||
if (cbResult) {
|
||||
ma_device_info 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);
|
||||
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
|
||||
}
|
||||
@@ -25140,6 +25168,7 @@ return_default_device:;
|
||||
if (cbResult) {
|
||||
ma_device_info 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);
|
||||
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
|
||||
}
|
||||
@@ -25238,10 +25267,12 @@ return_default_device:
|
||||
}
|
||||
}
|
||||
|
||||
/* Name / Description */
|
||||
/* ID and Name / Description */
|
||||
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);
|
||||
} else {
|
||||
pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
|
||||
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
|
||||
#endif
|
||||
|
||||
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 */
|
||||
pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8;
|
||||
((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->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels);
|
||||
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
|
||||
|
||||
locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE;
|
||||
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;
|
||||
|
||||
source.pLocator = &locatorDevice;
|
||||
@@ -25547,14 +25578,14 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf
|
||||
sink.pFormat = (SLDataFormat_PCM*)&pcm;
|
||||
|
||||
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. */
|
||||
pcm.formatType = SL_DATAFORMAT_PCM;
|
||||
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. */
|
||||
pcm.bitsPerSample = 16;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -25670,7 +25701,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf
|
||||
sink.pFormat = NULL;
|
||||
|
||||
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. */
|
||||
pcm.formatType = SL_DATAFORMAT_PCM;
|
||||
pcm.numChannels = 2;
|
||||
@@ -27783,7 +27814,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
ma_device_info deviceInfo;
|
||||
|
||||
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) {
|
||||
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1);
|
||||
} else {
|
||||
@@ -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) {
|
||||
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) {
|
||||
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1);
|
||||
} else {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/* Restricting this to debug output because it's a bit spamy and only really needed for debugging. */
|
||||
#if defined(MA_DEBUG_OUTPUT)
|
||||
{
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend));
|
||||
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
||||
char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
|
||||
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, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend));
|
||||
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_INFO, " 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, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels);
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate);
|
||||
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_INFO, " Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO");
|
||||
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_INFO, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO");
|
||||
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_INFO, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "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_INFO, " %s (%s)\n", pDevice->playback.name, "Playback");
|
||||
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_INFO, " Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels);
|
||||
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));
|
||||
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_INFO, " Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO");
|
||||
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_INFO, " Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO");
|
||||
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, " %s (%s)\n", name, "Capture");
|
||||
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_DEBUG, " Channels: %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels);
|
||||
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_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_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");
|
||||
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_DEBUG, " Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO");
|
||||
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_DEBUG, " Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO");
|
||||
}
|
||||
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
|
||||
char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
|
||||
ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL);
|
||||
|
||||
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_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_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);
|
||||
return MA_SUCCESS;
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
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_result result;
|
||||
@@ -35900,22 +36005,23 @@ MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma
|
||||
ma_spatializer_config config;
|
||||
|
||||
MA_ZERO_OBJECT(&config);
|
||||
config.channelsIn = channelsIn;
|
||||
config.channelsOut = channelsOut;
|
||||
config.pChannelMapIn = NULL;
|
||||
config.attenuationModel = ma_attenuation_model_inverse;
|
||||
config.positioning = ma_positioning_absolute;
|
||||
config.handedness = ma_handedness_right;
|
||||
config.minGain = 0;
|
||||
config.maxGain = 1;
|
||||
config.minDistance = 1;
|
||||
config.maxDistance = MA_FLT_MAX;
|
||||
config.rolloff = 1;
|
||||
config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */
|
||||
config.coneOuterAngleInRadians = 6.283185f; /* 360 degress. */
|
||||
config.coneOuterGain = 0.0f;
|
||||
config.dopplerFactor = 1;
|
||||
config.gainSmoothTimeInFrames = 360; /* 7.5ms @ 48K. */
|
||||
config.channelsIn = channelsIn;
|
||||
config.channelsOut = channelsOut;
|
||||
config.pChannelMapIn = NULL;
|
||||
config.attenuationModel = ma_attenuation_model_inverse;
|
||||
config.positioning = ma_positioning_absolute;
|
||||
config.handedness = ma_handedness_right;
|
||||
config.minGain = 0;
|
||||
config.maxGain = 1;
|
||||
config.minDistance = 1;
|
||||
config.maxDistance = MA_FLT_MAX;
|
||||
config.rolloff = 1;
|
||||
config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */
|
||||
config.coneOuterAngleInRadians = 6.283185f; /* 360 degress. */
|
||||
config.coneOuterGain = 0.0f;
|
||||
config.dopplerFactor = 1;
|
||||
config.directionalAttenuationFactor = 1;
|
||||
config.gainSmoothTimeInFrames = 360; /* 7.5ms @ 48K. */
|
||||
|
||||
return config;
|
||||
}
|
||||
@@ -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
|
||||
this for determining the factors to apply to each channel to apply the panning effect.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
ma_spatializer_get_relative_position_and_direction(pSpatializer, pListener, &relativePos, &relativeDir);
|
||||
}
|
||||
|
||||
distance = ma_vec3f_len(relativePos);
|
||||
@@ -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);
|
||||
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 {
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (pSpatializer == NULL) {
|
||||
@@ -36756,6 +36823,98 @@ MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer)
|
||||
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" {
|
||||
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
|
||||
#define DRFLAC_VERSION_MAJOR 0
|
||||
#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)
|
||||
#include <stddef.h>
|
||||
typedef signed char drflac_int8;
|
||||
@@ -45365,7 +45524,7 @@ typedef unsigned int drflac_uint32;
|
||||
#pragma GCC diagnostic pop
|
||||
#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;
|
||||
#else
|
||||
typedef drflac_uint32 drflac_uintptr;
|
||||
@@ -52454,7 +52613,7 @@ static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_m
|
||||
{
|
||||
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
|
||||
} else {
|
||||
while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -53590,7 +53749,7 @@ stage2:
|
||||
if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
|
||||
while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -54147,7 +54306,7 @@ MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manage
|
||||
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)
|
||||
@@ -54964,7 +55123,7 @@ MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manage
|
||||
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)
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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) {
|
||||
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
|
||||
ma_spatializer_listener_config listenerConfig;
|
||||
ma_uint32 iListener;
|
||||
|
||||
if (pEngine != NULL) {
|
||||
MA_ZERO_OBJECT(pEngine);
|
||||
if (pEngine == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pEngine);
|
||||
|
||||
/* The config is allowed to be NULL in which case we use defaults for everything. */
|
||||
if (pConfig != NULL) {
|
||||
engineConfig = *pConfig;
|
||||
@@ -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 (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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (pSound == NULL) {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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_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)
|
||||
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_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
|
||||
if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
|
||||
if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
|
||||
break;
|
||||
|
||||
+370
-219
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
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
|
||||
|
||||
@@ -20,7 +20,7 @@ extern "C" {
|
||||
|
||||
#define MA_VERSION_MAJOR 0
|
||||
#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)
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
@@ -36,39 +36,9 @@ extern "C" {
|
||||
#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
|
||||
#else
|
||||
#define MA_SIZEOF_PTR 4
|
||||
@@ -131,6 +101,56 @@ typedef ma_uint16 wchar_t;
|
||||
#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
|
||||
#define MA_INLINE __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
@@ -247,148 +267,152 @@ typedef struct ma_context ma_context;
|
||||
typedef struct ma_device ma_device;
|
||||
|
||||
typedef ma_uint8 ma_channel;
|
||||
#define MA_CHANNEL_NONE 0
|
||||
#define MA_CHANNEL_MONO 1
|
||||
#define MA_CHANNEL_FRONT_LEFT 2
|
||||
#define MA_CHANNEL_FRONT_RIGHT 3
|
||||
#define MA_CHANNEL_FRONT_CENTER 4
|
||||
#define MA_CHANNEL_LFE 5
|
||||
#define MA_CHANNEL_BACK_LEFT 6
|
||||
#define MA_CHANNEL_BACK_RIGHT 7
|
||||
#define MA_CHANNEL_FRONT_LEFT_CENTER 8
|
||||
#define MA_CHANNEL_FRONT_RIGHT_CENTER 9
|
||||
#define MA_CHANNEL_BACK_CENTER 10
|
||||
#define MA_CHANNEL_SIDE_LEFT 11
|
||||
#define MA_CHANNEL_SIDE_RIGHT 12
|
||||
#define MA_CHANNEL_TOP_CENTER 13
|
||||
#define MA_CHANNEL_TOP_FRONT_LEFT 14
|
||||
#define MA_CHANNEL_TOP_FRONT_CENTER 15
|
||||
#define MA_CHANNEL_TOP_FRONT_RIGHT 16
|
||||
#define MA_CHANNEL_TOP_BACK_LEFT 17
|
||||
#define MA_CHANNEL_TOP_BACK_CENTER 18
|
||||
#define MA_CHANNEL_TOP_BACK_RIGHT 19
|
||||
#define MA_CHANNEL_AUX_0 20
|
||||
#define MA_CHANNEL_AUX_1 21
|
||||
#define MA_CHANNEL_AUX_2 22
|
||||
#define MA_CHANNEL_AUX_3 23
|
||||
#define MA_CHANNEL_AUX_4 24
|
||||
#define MA_CHANNEL_AUX_5 25
|
||||
#define MA_CHANNEL_AUX_6 26
|
||||
#define MA_CHANNEL_AUX_7 27
|
||||
#define MA_CHANNEL_AUX_8 28
|
||||
#define MA_CHANNEL_AUX_9 29
|
||||
#define MA_CHANNEL_AUX_10 30
|
||||
#define MA_CHANNEL_AUX_11 31
|
||||
#define MA_CHANNEL_AUX_12 32
|
||||
#define MA_CHANNEL_AUX_13 33
|
||||
#define MA_CHANNEL_AUX_14 34
|
||||
#define MA_CHANNEL_AUX_15 35
|
||||
#define MA_CHANNEL_AUX_16 36
|
||||
#define MA_CHANNEL_AUX_17 37
|
||||
#define MA_CHANNEL_AUX_18 38
|
||||
#define MA_CHANNEL_AUX_19 39
|
||||
#define MA_CHANNEL_AUX_20 40
|
||||
#define MA_CHANNEL_AUX_21 41
|
||||
#define MA_CHANNEL_AUX_22 42
|
||||
#define MA_CHANNEL_AUX_23 43
|
||||
#define MA_CHANNEL_AUX_24 44
|
||||
#define MA_CHANNEL_AUX_25 45
|
||||
#define MA_CHANNEL_AUX_26 46
|
||||
#define MA_CHANNEL_AUX_27 47
|
||||
#define MA_CHANNEL_AUX_28 48
|
||||
#define MA_CHANNEL_AUX_29 49
|
||||
#define MA_CHANNEL_AUX_30 50
|
||||
#define MA_CHANNEL_AUX_31 51
|
||||
#define MA_CHANNEL_LEFT MA_CHANNEL_FRONT_LEFT
|
||||
#define MA_CHANNEL_RIGHT MA_CHANNEL_FRONT_RIGHT
|
||||
#define MA_CHANNEL_POSITION_COUNT (MA_CHANNEL_AUX_31 + 1)
|
||||
typedef enum
|
||||
{
|
||||
MA_CHANNEL_NONE = 0,
|
||||
MA_CHANNEL_MONO = 1,
|
||||
MA_CHANNEL_FRONT_LEFT = 2,
|
||||
MA_CHANNEL_FRONT_RIGHT = 3,
|
||||
MA_CHANNEL_FRONT_CENTER = 4,
|
||||
MA_CHANNEL_LFE = 5,
|
||||
MA_CHANNEL_BACK_LEFT = 6,
|
||||
MA_CHANNEL_BACK_RIGHT = 7,
|
||||
MA_CHANNEL_FRONT_LEFT_CENTER = 8,
|
||||
MA_CHANNEL_FRONT_RIGHT_CENTER = 9,
|
||||
MA_CHANNEL_BACK_CENTER = 10,
|
||||
MA_CHANNEL_SIDE_LEFT = 11,
|
||||
MA_CHANNEL_SIDE_RIGHT = 12,
|
||||
MA_CHANNEL_TOP_CENTER = 13,
|
||||
MA_CHANNEL_TOP_FRONT_LEFT = 14,
|
||||
MA_CHANNEL_TOP_FRONT_CENTER = 15,
|
||||
MA_CHANNEL_TOP_FRONT_RIGHT = 16,
|
||||
MA_CHANNEL_TOP_BACK_LEFT = 17,
|
||||
MA_CHANNEL_TOP_BACK_CENTER = 18,
|
||||
MA_CHANNEL_TOP_BACK_RIGHT = 19,
|
||||
MA_CHANNEL_AUX_0 = 20,
|
||||
MA_CHANNEL_AUX_1 = 21,
|
||||
MA_CHANNEL_AUX_2 = 22,
|
||||
MA_CHANNEL_AUX_3 = 23,
|
||||
MA_CHANNEL_AUX_4 = 24,
|
||||
MA_CHANNEL_AUX_5 = 25,
|
||||
MA_CHANNEL_AUX_6 = 26,
|
||||
MA_CHANNEL_AUX_7 = 27,
|
||||
MA_CHANNEL_AUX_8 = 28,
|
||||
MA_CHANNEL_AUX_9 = 29,
|
||||
MA_CHANNEL_AUX_10 = 30,
|
||||
MA_CHANNEL_AUX_11 = 31,
|
||||
MA_CHANNEL_AUX_12 = 32,
|
||||
MA_CHANNEL_AUX_13 = 33,
|
||||
MA_CHANNEL_AUX_14 = 34,
|
||||
MA_CHANNEL_AUX_15 = 35,
|
||||
MA_CHANNEL_AUX_16 = 36,
|
||||
MA_CHANNEL_AUX_17 = 37,
|
||||
MA_CHANNEL_AUX_18 = 38,
|
||||
MA_CHANNEL_AUX_19 = 39,
|
||||
MA_CHANNEL_AUX_20 = 40,
|
||||
MA_CHANNEL_AUX_21 = 41,
|
||||
MA_CHANNEL_AUX_22 = 42,
|
||||
MA_CHANNEL_AUX_23 = 43,
|
||||
MA_CHANNEL_AUX_24 = 44,
|
||||
MA_CHANNEL_AUX_25 = 45,
|
||||
MA_CHANNEL_AUX_26 = 46,
|
||||
MA_CHANNEL_AUX_27 = 47,
|
||||
MA_CHANNEL_AUX_28 = 48,
|
||||
MA_CHANNEL_AUX_29 = 49,
|
||||
MA_CHANNEL_AUX_30 = 50,
|
||||
MA_CHANNEL_AUX_31 = 51,
|
||||
MA_CHANNEL_LEFT = MA_CHANNEL_FRONT_LEFT,
|
||||
MA_CHANNEL_RIGHT = MA_CHANNEL_FRONT_RIGHT,
|
||||
MA_CHANNEL_POSITION_COUNT = (MA_CHANNEL_AUX_31 + 1)
|
||||
} _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MA_SUCCESS = 0,
|
||||
MA_ERROR = -1, /* A generic error. */
|
||||
MA_INVALID_ARGS = -2,
|
||||
MA_INVALID_OPERATION = -3,
|
||||
MA_OUT_OF_MEMORY = -4,
|
||||
MA_OUT_OF_RANGE = -5,
|
||||
MA_ACCESS_DENIED = -6,
|
||||
MA_DOES_NOT_EXIST = -7,
|
||||
MA_ALREADY_EXISTS = -8,
|
||||
MA_TOO_MANY_OPEN_FILES = -9,
|
||||
MA_INVALID_FILE = -10,
|
||||
MA_TOO_BIG = -11,
|
||||
MA_PATH_TOO_LONG = -12,
|
||||
MA_NAME_TOO_LONG = -13,
|
||||
MA_NOT_DIRECTORY = -14,
|
||||
MA_IS_DIRECTORY = -15,
|
||||
MA_DIRECTORY_NOT_EMPTY = -16,
|
||||
MA_AT_END = -17,
|
||||
MA_NO_SPACE = -18,
|
||||
MA_BUSY = -19,
|
||||
MA_IO_ERROR = -20,
|
||||
MA_INTERRUPT = -21,
|
||||
MA_UNAVAILABLE = -22,
|
||||
MA_ALREADY_IN_USE = -23,
|
||||
MA_BAD_ADDRESS = -24,
|
||||
MA_BAD_SEEK = -25,
|
||||
MA_BAD_PIPE = -26,
|
||||
MA_DEADLOCK = -27,
|
||||
MA_TOO_MANY_LINKS = -28,
|
||||
MA_NOT_IMPLEMENTED = -29,
|
||||
MA_NO_MESSAGE = -30,
|
||||
MA_BAD_MESSAGE = -31,
|
||||
MA_NO_DATA_AVAILABLE = -32,
|
||||
MA_INVALID_DATA = -33,
|
||||
MA_TIMEOUT = -34,
|
||||
MA_NO_NETWORK = -35,
|
||||
MA_NOT_UNIQUE = -36,
|
||||
MA_NOT_SOCKET = -37,
|
||||
MA_NO_ADDRESS = -38,
|
||||
MA_BAD_PROTOCOL = -39,
|
||||
MA_PROTOCOL_UNAVAILABLE = -40,
|
||||
MA_PROTOCOL_NOT_SUPPORTED = -41,
|
||||
MA_PROTOCOL_FAMILY_NOT_SUPPORTED = -42,
|
||||
MA_ADDRESS_FAMILY_NOT_SUPPORTED = -43,
|
||||
MA_SOCKET_NOT_SUPPORTED = -44,
|
||||
MA_CONNECTION_RESET = -45,
|
||||
MA_ALREADY_CONNECTED = -46,
|
||||
MA_NOT_CONNECTED = -47,
|
||||
MA_CONNECTION_REFUSED = -48,
|
||||
MA_NO_HOST = -49,
|
||||
MA_IN_PROGRESS = -50,
|
||||
MA_CANCELLED = -51,
|
||||
MA_MEMORY_ALREADY_MAPPED = -52,
|
||||
|
||||
/* General miniaudio-specific errors. */
|
||||
MA_FORMAT_NOT_SUPPORTED = -100,
|
||||
MA_DEVICE_TYPE_NOT_SUPPORTED = -101,
|
||||
MA_SHARE_MODE_NOT_SUPPORTED = -102,
|
||||
MA_NO_BACKEND = -103,
|
||||
MA_NO_DEVICE = -104,
|
||||
MA_API_NOT_FOUND = -105,
|
||||
MA_INVALID_DEVICE_CONFIG = -106,
|
||||
MA_LOOP = -107,
|
||||
|
||||
/* State errors. */
|
||||
MA_DEVICE_NOT_INITIALIZED = -200,
|
||||
MA_DEVICE_ALREADY_INITIALIZED = -201,
|
||||
MA_DEVICE_NOT_STARTED = -202,
|
||||
MA_DEVICE_NOT_STOPPED = -203,
|
||||
|
||||
/* Operation errors. */
|
||||
MA_FAILED_TO_INIT_BACKEND = -300,
|
||||
MA_FAILED_TO_OPEN_BACKEND_DEVICE = -301,
|
||||
MA_FAILED_TO_START_BACKEND_DEVICE = -302,
|
||||
MA_FAILED_TO_STOP_BACKEND_DEVICE = -303
|
||||
} ma_result;
|
||||
|
||||
|
||||
typedef int ma_result;
|
||||
#define MA_SUCCESS 0
|
||||
#define MA_ERROR -1 /* A generic error. */
|
||||
#define MA_INVALID_ARGS -2
|
||||
#define MA_INVALID_OPERATION -3
|
||||
#define MA_OUT_OF_MEMORY -4
|
||||
#define MA_OUT_OF_RANGE -5
|
||||
#define MA_ACCESS_DENIED -6
|
||||
#define MA_DOES_NOT_EXIST -7
|
||||
#define MA_ALREADY_EXISTS -8
|
||||
#define MA_TOO_MANY_OPEN_FILES -9
|
||||
#define MA_INVALID_FILE -10
|
||||
#define MA_TOO_BIG -11
|
||||
#define MA_PATH_TOO_LONG -12
|
||||
#define MA_NAME_TOO_LONG -13
|
||||
#define MA_NOT_DIRECTORY -14
|
||||
#define MA_IS_DIRECTORY -15
|
||||
#define MA_DIRECTORY_NOT_EMPTY -16
|
||||
#define MA_AT_END -17
|
||||
#define MA_NO_SPACE -18
|
||||
#define MA_BUSY -19
|
||||
#define MA_IO_ERROR -20
|
||||
#define MA_INTERRUPT -21
|
||||
#define MA_UNAVAILABLE -22
|
||||
#define MA_ALREADY_IN_USE -23
|
||||
#define MA_BAD_ADDRESS -24
|
||||
#define MA_BAD_SEEK -25
|
||||
#define MA_BAD_PIPE -26
|
||||
#define MA_DEADLOCK -27
|
||||
#define MA_TOO_MANY_LINKS -28
|
||||
#define MA_NOT_IMPLEMENTED -29
|
||||
#define MA_NO_MESSAGE -30
|
||||
#define MA_BAD_MESSAGE -31
|
||||
#define MA_NO_DATA_AVAILABLE -32
|
||||
#define MA_INVALID_DATA -33
|
||||
#define MA_TIMEOUT -34
|
||||
#define MA_NO_NETWORK -35
|
||||
#define MA_NOT_UNIQUE -36
|
||||
#define MA_NOT_SOCKET -37
|
||||
#define MA_NO_ADDRESS -38
|
||||
#define MA_BAD_PROTOCOL -39
|
||||
#define MA_PROTOCOL_UNAVAILABLE -40
|
||||
#define MA_PROTOCOL_NOT_SUPPORTED -41
|
||||
#define MA_PROTOCOL_FAMILY_NOT_SUPPORTED -42
|
||||
#define MA_ADDRESS_FAMILY_NOT_SUPPORTED -43
|
||||
#define MA_SOCKET_NOT_SUPPORTED -44
|
||||
#define MA_CONNECTION_RESET -45
|
||||
#define MA_ALREADY_CONNECTED -46
|
||||
#define MA_NOT_CONNECTED -47
|
||||
#define MA_CONNECTION_REFUSED -48
|
||||
#define MA_NO_HOST -49
|
||||
#define MA_IN_PROGRESS -50
|
||||
#define MA_CANCELLED -51
|
||||
#define MA_MEMORY_ALREADY_MAPPED -52
|
||||
|
||||
/* General miniaudio-specific errors. */
|
||||
#define MA_FORMAT_NOT_SUPPORTED -100
|
||||
#define MA_DEVICE_TYPE_NOT_SUPPORTED -101
|
||||
#define MA_SHARE_MODE_NOT_SUPPORTED -102
|
||||
#define MA_NO_BACKEND -103
|
||||
#define MA_NO_DEVICE -104
|
||||
#define MA_API_NOT_FOUND -105
|
||||
#define MA_INVALID_DEVICE_CONFIG -106
|
||||
#define MA_LOOP -107
|
||||
|
||||
/* State errors. */
|
||||
#define MA_DEVICE_NOT_INITIALIZED -200
|
||||
#define MA_DEVICE_ALREADY_INITIALIZED -201
|
||||
#define MA_DEVICE_NOT_STARTED -202
|
||||
#define MA_DEVICE_NOT_STOPPED -203
|
||||
|
||||
/* Operation errors. */
|
||||
#define MA_FAILED_TO_INIT_BACKEND -300
|
||||
#define MA_FAILED_TO_OPEN_BACKEND_DEVICE -301
|
||||
#define MA_FAILED_TO_START_BACKEND_DEVICE -302
|
||||
#define MA_FAILED_TO_STOP_BACKEND_DEVICE -303
|
||||
|
||||
|
||||
#define MA_MIN_CHANNELS 1
|
||||
#ifndef MA_MAX_CHANNELS
|
||||
#define MA_MAX_CHANNELS 254
|
||||
#define MA_MIN_CHANNELS 1
|
||||
#ifndef MA_MAX_CHANNELS
|
||||
#define MA_MAX_CHANNELS 254
|
||||
#endif
|
||||
|
||||
#ifndef MA_MAX_FILTER_ORDER
|
||||
#define MA_MAX_FILTER_ORDER 8
|
||||
#define MA_MAX_FILTER_ORDER 8
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
@@ -515,14 +539,14 @@ typedef enum
|
||||
typedef ma_handle ma_thread;
|
||||
#endif
|
||||
#if defined(MA_POSIX)
|
||||
typedef pthread_t ma_thread;
|
||||
typedef ma_pthread_t ma_thread;
|
||||
#endif
|
||||
|
||||
#if defined(MA_WIN32)
|
||||
typedef ma_handle ma_mutex;
|
||||
#endif
|
||||
#if defined(MA_POSIX)
|
||||
typedef pthread_mutex_t ma_mutex;
|
||||
typedef ma_pthread_mutex_t ma_mutex;
|
||||
#endif
|
||||
|
||||
#if defined(MA_WIN32)
|
||||
@@ -532,8 +556,8 @@ typedef ma_handle ma_event;
|
||||
typedef struct
|
||||
{
|
||||
ma_uint32 value;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
ma_pthread_mutex_t lock;
|
||||
ma_pthread_cond_t cond;
|
||||
} ma_event;
|
||||
#endif /* MA_POSIX */
|
||||
|
||||
@@ -544,8 +568,8 @@ typedef ma_handle ma_semaphore;
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
ma_pthread_mutex_t lock;
|
||||
ma_pthread_cond_t cond;
|
||||
} ma_semaphore;
|
||||
#endif /* MA_POSIX */
|
||||
#else
|
||||
@@ -1280,7 +1304,8 @@ typedef struct
|
||||
float coneInnerAngleInRadians;
|
||||
float coneOuterAngleInRadians;
|
||||
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_spatializer_config;
|
||||
|
||||
@@ -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_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor);
|
||||
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 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 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 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;
|
||||
|
||||
#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
|
||||
{
|
||||
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
|
||||
ma_device_id id;
|
||||
char name[256];
|
||||
char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* +1 for null terminator. */
|
||||
ma_bool32 isDefault;
|
||||
|
||||
ma_uint32 nativeDataFormatCount;
|
||||
@@ -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
|
||||
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
|
||||
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,
|
||||
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
|
||||
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
|
||||
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
|
||||
{
|
||||
@@ -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 (* onDeviceDataLoop)(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
|
||||
@@ -3029,7 +3065,7 @@ struct ma_device
|
||||
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. */
|
||||
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_format format;
|
||||
ma_uint32 channels;
|
||||
@@ -3050,7 +3086,7 @@ struct ma_device
|
||||
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. */
|
||||
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_format format;
|
||||
ma_uint32 channels;
|
||||
@@ -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);
|
||||
|
||||
|
||||
/*
|
||||
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.
|
||||
|
||||
@@ -5269,8 +5394,11 @@ appropriate for a given situation.
|
||||
typedef void ma_vfs;
|
||||
typedef ma_handle ma_vfs_file;
|
||||
|
||||
#define MA_OPEN_MODE_READ 0x00000001
|
||||
#define MA_OPEN_MODE_WRITE 0x00000002
|
||||
typedef enum
|
||||
{
|
||||
MA_OPEN_MODE_READ = 0x00000001,
|
||||
MA_OPEN_MODE_WRITE = 0x00000002
|
||||
} ma_open_mode_flags;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -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_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. */
|
||||
#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. */
|
||||
#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(). */
|
||||
typedef enum
|
||||
{
|
||||
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. */
|
||||
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
|
||||
#define MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE 0x00000001
|
||||
#define MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE 0x00000002
|
||||
#define MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE 0x00000003
|
||||
#define MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER 0x00000004
|
||||
#define MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER 0x00000005
|
||||
#define MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM 0x00000006
|
||||
#define MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM 0x00000007
|
||||
#define MA_RESOURCE_MANAGER_JOB_PAGE_DATA_STREAM 0x00000008
|
||||
#define MA_RESOURCE_MANAGER_JOB_SEEK_DATA_STREAM 0x00000009
|
||||
#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. */
|
||||
typedef enum
|
||||
{
|
||||
MA_RESOURCE_MANAGER_JOB_QUIT = 0x00000000,
|
||||
MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE = 0x00000001,
|
||||
MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE = 0x00000002,
|
||||
MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE = 0x00000003,
|
||||
MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER = 0x00000004,
|
||||
MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER = 0x00000005,
|
||||
MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM = 0x00000006,
|
||||
MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM = 0x00000007,
|
||||
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
|
||||
|
||||
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
|
||||
{
|
||||
@@ -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
|
||||
#endif
|
||||
|
||||
/* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
|
||||
#define MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING 0x00000001
|
||||
|
||||
/* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */
|
||||
#define MA_RESOURCE_MANAGER_FLAG_NO_THREADING 0x00000002
|
||||
typedef enum
|
||||
{
|
||||
/* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
|
||||
MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING = 0x00000001,
|
||||
|
||||
/* 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
|
||||
{
|
||||
@@ -6113,10 +6252,13 @@ typedef void ma_node;
|
||||
|
||||
|
||||
/* Node flags. */
|
||||
#define MA_NODE_FLAG_PASSTHROUGH 0x00000001
|
||||
#define MA_NODE_FLAG_CONTINUOUS_PROCESSING 0x00000002
|
||||
#define MA_NODE_FLAG_ALLOW_NULL_INPUT 0x00000004
|
||||
#define MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES 0x00000008
|
||||
typedef enum
|
||||
{
|
||||
MA_NODE_FLAG_PASSTHROUGH = 0x00000001,
|
||||
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. */
|
||||
@@ -6132,7 +6274,7 @@ typedef struct
|
||||
/*
|
||||
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
|
||||
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
|
||||
`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);
|
||||
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.
|
||||
*/
|
||||
#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;
|
||||
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. */
|
||||
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_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. */
|
||||
@@ -6569,13 +6709,16 @@ typedef struct ma_sound ma_sound;
|
||||
|
||||
|
||||
/* Sound flags. */
|
||||
#define MA_SOUND_FLAG_STREAM MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM /* 0x00000001 */
|
||||
#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 */
|
||||
#define MA_SOUND_FLAG_WAIT_INIT MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT /* 0x00000008 */
|
||||
#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. */
|
||||
#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. */
|
||||
#define MA_SOUND_FLAG_NO_SPATIALIZATION 0x00000040 /* Disable spatialization. */
|
||||
typedef enum
|
||||
{
|
||||
MA_SOUND_FLAG_STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */
|
||||
MA_SOUND_FLAG_DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */
|
||||
MA_SOUND_FLAG_ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */
|
||||
MA_SOUND_FLAG_WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */
|
||||
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
|
||||
#define MA_ENGINE_MAX_LISTENERS 4
|
||||
@@ -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 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_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 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);
|
||||
@@ -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_set_doppler_factor(ma_sound* pSound, float dopplerFactor);
|
||||
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_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds);
|
||||
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
|
||||
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 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 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);
|
||||
@@ -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_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 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_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);
|
||||
|
||||
Reference in New Issue
Block a user