mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
Merge branch 'dev' of https://github.com/mackron/miniaudio into dev
This commit is contained in:
+70
-40
@@ -38,7 +38,7 @@ A config/init pattern is used throughout the entire library. The idea is that yo
|
||||
object and pass that into the initialization routine. The advantage to this system is that the
|
||||
config object can be initialized with logical defaults and new properties added to it without
|
||||
breaking the API. The config object can be allocated on the stack and does not need to be
|
||||
maintained after initialization of the corresponding object.
|
||||
maintained after initialization of the corresponding object.
|
||||
|
||||
|
||||
1.1. Low Level API
|
||||
@@ -363,7 +363,7 @@ initialized. The easiest but least flexible way of playing a sound is like so:
|
||||
This plays what miniaudio calls an "inline" sound. It plays the sound once, and then puts the
|
||||
internal sound up for recycling. The last parameter is used to specify which sound group the sound
|
||||
should be associated with which will be explained later. This particular way of playing a sound is
|
||||
simple, but lacks flexibility and features. A more flexible way of playing a sound is to first
|
||||
simple, but lacks flexibility and features. A more flexible way of playing a sound is to first
|
||||
initialize a sound:
|
||||
|
||||
```c
|
||||
@@ -824,7 +824,7 @@ retrieved like so:
|
||||
ma_uint32 channels;
|
||||
ma_uint32 sampleRate;
|
||||
ma_channel channelMap[MA_MAX_CHANNELS];
|
||||
|
||||
|
||||
result = ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; // Failed to retrieve data format.
|
||||
@@ -880,7 +880,7 @@ To do this, you can use chaining:
|
||||
```
|
||||
|
||||
In the example above we're using decoders. When reading from a chain, you always want to read from
|
||||
the top level data source in the chain. In the example above, `decoder1` is the top level data
|
||||
the top level data source in the chain. In the example above, `decoder1` is the top level data
|
||||
source in the chain. When `decoder1` reaches the end, `decoder2` will start seamlessly without any
|
||||
gaps.
|
||||
|
||||
@@ -973,7 +973,7 @@ base object (`ma_data_source_base`):
|
||||
void my_data_source_uninit(my_data_source* pMyDataSource)
|
||||
{
|
||||
// ... do the uninitialization of your custom data source here ...
|
||||
|
||||
|
||||
// You must uninitialize the base data source.
|
||||
ma_data_source_uninit(&pMyDataSource->base);
|
||||
}
|
||||
@@ -2563,7 +2563,7 @@ The `ma_decoding_backend_vtable` vtable has the following functions:
|
||||
|
||||
```
|
||||
onInit
|
||||
onInitFile
|
||||
onInitFile
|
||||
onInitFileW
|
||||
onInitMemory
|
||||
onUninit
|
||||
@@ -3700,7 +3700,7 @@ extern "C" {
|
||||
#pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */
|
||||
#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__)
|
||||
@@ -3816,7 +3816,11 @@ typedef ma_uint16 wchar_t;
|
||||
|
||||
#ifdef __unix__
|
||||
#define MA_UNIX
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#ifdef __ORBIS__
|
||||
#define MA_ORBIS
|
||||
#elif defined(__PROSPERO__)
|
||||
#define MA_PROSPERO
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#define MA_BSD
|
||||
#endif
|
||||
#endif
|
||||
@@ -4100,7 +4104,7 @@ typedef enum
|
||||
|
||||
|
||||
#define MA_MIN_CHANNELS 1
|
||||
#ifndef MA_MAX_CHANNELS
|
||||
#ifndef MA_MAX_CHANNELS
|
||||
#define MA_MAX_CHANNELS 254
|
||||
#endif
|
||||
|
||||
@@ -6224,7 +6228,7 @@ This section contains the APIs for device playback and capture. Here is where yo
|
||||
#define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
|
||||
#endif
|
||||
#endif
|
||||
#if defined(MA_UNIX)
|
||||
#if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO)
|
||||
#if defined(MA_LINUX)
|
||||
#if !defined(MA_ANDROID) /* ALSA is not supported on Android. */
|
||||
#define MA_SUPPORT_ALSA
|
||||
@@ -17411,6 +17415,14 @@ DEVICE I/O
|
||||
|
||||
*************************************************************************************************************************************************************
|
||||
************************************************************************************************************************************************************/
|
||||
|
||||
/* Disable run-time linking on certain backends and platforms. */
|
||||
#ifndef MA_NO_RUNTIME_LINKING
|
||||
#if defined(MA_EMSCRIPTEN) || defined(MA_ORBIS) || defined(MA_PROSPERO)
|
||||
#define MA_NO_RUNTIME_LINKING
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MA_NO_DEVICE_IO
|
||||
#ifdef MA_WIN32
|
||||
#include <objbase.h>
|
||||
@@ -17429,18 +17441,15 @@ DEVICE I/O
|
||||
#ifdef MA_POSIX
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable run-time linking on certain backends. */
|
||||
#ifndef MA_NO_RUNTIME_LINKING
|
||||
#if defined(MA_EMSCRIPTEN)
|
||||
#define MA_NO_RUNTIME_LINKING
|
||||
/* No need for dlfcn.h if we're not using runtime linking. */
|
||||
#ifndef MA_NO_RUNTIME_LINKING
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags)
|
||||
{
|
||||
if (pDeviceInfo == NULL) {
|
||||
@@ -17975,6 +17984,7 @@ Dynamic Linking
|
||||
*******************************************************************************/
|
||||
MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename)
|
||||
{
|
||||
#ifndef MA_NO_RUNTIME_LINKING
|
||||
ma_handle handle;
|
||||
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename);
|
||||
@@ -18006,10 +18016,17 @@ MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename)
|
||||
|
||||
(void)pContext; /* It's possible for pContext to be unused. */
|
||||
return handle;
|
||||
#else
|
||||
/* Runtime linking is disabled. */
|
||||
(void)pContext;
|
||||
(void)filename;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
MA_API void ma_dlclose(ma_context* pContext, ma_handle handle)
|
||||
{
|
||||
#ifndef MA_NO_RUNTIME_LINKING
|
||||
#ifdef _WIN32
|
||||
FreeLibrary((HMODULE)handle);
|
||||
#else
|
||||
@@ -18017,10 +18034,16 @@ MA_API void ma_dlclose(ma_context* pContext, ma_handle handle)
|
||||
#endif
|
||||
|
||||
(void)pContext;
|
||||
#else
|
||||
/* Runtime linking is disabled. */
|
||||
(void)pContext;
|
||||
(void)handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol)
|
||||
{
|
||||
#ifndef MA_NO_RUNTIME_LINKING
|
||||
ma_proc proc;
|
||||
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol);
|
||||
@@ -18044,6 +18067,13 @@ MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symb
|
||||
|
||||
(void)pContext; /* It's possible for pContext to be unused. */
|
||||
return proc;
|
||||
#else
|
||||
/* Runtime linking is disabled. */
|
||||
(void)pContext;
|
||||
(void)handle;
|
||||
(void)symbol;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -18248,7 +18278,7 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void*
|
||||
/* The intermediary buffer has just been filled. */
|
||||
pDevice->playback.intermediaryBufferLen = pDevice->playback.intermediaryBufferCap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're in duplex mode we might need to do a refill of the data. */
|
||||
@@ -29569,7 +29599,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
|
||||
sampleRate = pDescriptorCapture->sampleRate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
result = ma_init_pa_mainloop_and_pa_context__pulse(pDevice->pContext, pDevice->pContext->pulse.pApplicationName, pDevice->pContext->pulse.pServerName, MA_FALSE, &pDevice->pulse.pMainLoop, &pDevice->pulse.pPulseContext);
|
||||
if (result != MA_SUCCESS) {
|
||||
@@ -32707,7 +32737,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.\n");
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList;
|
||||
MA_ASSERT(pRenderedBufferList);
|
||||
|
||||
@@ -33145,7 +33175,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
|
||||
*/
|
||||
ma_device__on_notification_interruption_began(m_pDevice);
|
||||
} break;
|
||||
|
||||
|
||||
case AVAudioSessionInterruptionTypeEnded:
|
||||
{
|
||||
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n");
|
||||
@@ -33199,7 +33229,7 @@ static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
|
||||
}
|
||||
|
||||
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels);
|
||||
|
||||
|
||||
/* Let the application know about the route change. */
|
||||
ma_device__on_notification_rerouted(m_pDevice);
|
||||
}
|
||||
@@ -33572,7 +33602,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
|
||||
@autoreleasepool {
|
||||
AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
|
||||
MA_ASSERT(pAudioSession != NULL);
|
||||
|
||||
|
||||
[pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil];
|
||||
actualPeriodSizeInFrames = ma_next_power_of_2((ma_uint32)(pAudioSession.IOBufferDuration * pAudioSession.sampleRate));
|
||||
}
|
||||
@@ -33813,7 +33843,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c
|
||||
|
||||
#if defined(MA_APPLE_DESKTOP)
|
||||
ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio);
|
||||
|
||||
|
||||
/*
|
||||
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
|
||||
switch the device in the background.
|
||||
@@ -33877,7 +33907,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c
|
||||
|
||||
#if defined(MA_APPLE_DESKTOP)
|
||||
ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio);
|
||||
|
||||
|
||||
/*
|
||||
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
|
||||
switch the device in the background.
|
||||
@@ -37465,7 +37495,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
(void)pConfig;
|
||||
return MA_SUCCESS;
|
||||
@@ -39959,7 +39989,7 @@ MA_API ma_result ma_device_job_thread_init(const ma_device_job_thread_config* pC
|
||||
|
||||
|
||||
/* Initialize the job queue before the thread to ensure it's in a valid state. */
|
||||
jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity);
|
||||
jobQueueConfig = ma_job_queue_config_init(pConfig->jobQueueFlags, pConfig->jobQueueCapacity);
|
||||
|
||||
result = ma_job_queue_init(&jobQueueConfig, pAllocationCallbacks, &pJobThread->jobQueue);
|
||||
if (result != MA_SUCCESS) {
|
||||
@@ -40767,7 +40797,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) {
|
||||
ma_uint64 intermediaryBufferSizeInBytes;
|
||||
|
||||
|
||||
pDevice->playback.intermediaryBufferLen = 0;
|
||||
if (pConfig->deviceType == ma_device_type_duplex) {
|
||||
pDevice->playback.intermediaryBufferCap = pDevice->capture.intermediaryBufferCap; /* In duplex mode, make sure the intermediary buffer is always the same size as the capture side. */
|
||||
@@ -40779,7 +40809,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
|
||||
}
|
||||
|
||||
intermediaryBufferSizeInBytes = pDevice->playback.intermediaryBufferCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
|
||||
|
||||
|
||||
pDevice->playback.pIntermediaryBuffer = ma_malloc((size_t)intermediaryBufferSizeInBytes, &pContext->allocationCallbacks);
|
||||
if (pDevice->playback.pIntermediaryBuffer == NULL) {
|
||||
ma_device_uninit(pDevice);
|
||||
@@ -51994,7 +52024,7 @@ MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_convert
|
||||
/*
|
||||
We now need to fill out our weights table. This is determined by the mixing mode.
|
||||
*/
|
||||
|
||||
|
||||
/* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */
|
||||
for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
|
||||
ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn);
|
||||
@@ -67091,7 +67121,7 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man
|
||||
pDataBuffer->seekToCursorOnNextRead = MA_TRUE; /* Keep the seek scheduled. We just haven't loaded enough data yet to do the seek properly. */
|
||||
return MA_BUSY;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -67637,7 +67667,7 @@ MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pReso
|
||||
config.pFilePath = pFilePath;
|
||||
config.flags = flags;
|
||||
config.pNotifications = pNotifications;
|
||||
|
||||
|
||||
return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream);
|
||||
}
|
||||
|
||||
@@ -67649,7 +67679,7 @@ MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pRe
|
||||
config.pFilePathW = pFilePath;
|
||||
config.flags = flags;
|
||||
config.pNotifications = pNotifications;
|
||||
|
||||
|
||||
return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream);
|
||||
}
|
||||
|
||||
@@ -68762,7 +68792,7 @@ static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob
|
||||
There is a hole between here and the where the data connector is initialized where the data
|
||||
buffer node may have finished initializing. We need to check for this by checking the result of
|
||||
the data buffer node and whether or not we had an unknown data supply type at the time of
|
||||
trying to initialize the data connector.
|
||||
trying to initialize the data connector.
|
||||
*/
|
||||
result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode);
|
||||
if (result == MA_BUSY || (result == MA_SUCCESS && isConnectorInitialized == MA_FALSE && dataSupplyType == ma_resource_manager_data_supply_type_unknown)) {
|
||||
@@ -70878,7 +70908,7 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
|
||||
ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[outputBusIndex], MA_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Apply volume, if necessary. */
|
||||
ma_apply_volume_factor_f32(pFramesOut, totalFramesRead * ma_node_get_output_channels(pNodeBase, outputBusIndex), ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex]));
|
||||
|
||||
@@ -72481,7 +72511,7 @@ static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pCo
|
||||
/* Resmapler. */
|
||||
resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, channelsIn, 1, 1); /* Input and output sample rates don't affect the calculation of the heap size. */
|
||||
resamplerConfig.lpfOrder = 0;
|
||||
|
||||
|
||||
result = ma_linear_resampler_get_heap_size(&resamplerConfig, &tempHeapSize);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; /* Failed to retrieve the size of the heap for the resampler. */
|
||||
@@ -72717,7 +72747,7 @@ MA_API ma_sound_config ma_sound_config_init_2(ma_engine* pEngine)
|
||||
} else {
|
||||
config.monoExpansionMode = ma_mono_expansion_mode_default;
|
||||
}
|
||||
|
||||
|
||||
config.rangeEndInPCMFrames = ~((ma_uint64)0);
|
||||
config.loopPointEndInPCMFrames = ~((ma_uint64)0);
|
||||
|
||||
@@ -72825,7 +72855,7 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng
|
||||
#if !defined(MA_NO_DEVICE_IO)
|
||||
{
|
||||
pEngine->pDevice = engineConfig.pDevice;
|
||||
|
||||
|
||||
/* If we don't have a device, we need one. */
|
||||
if (pEngine->pDevice == NULL && engineConfig.noDevice == MA_FALSE) {
|
||||
ma_device_config deviceConfig;
|
||||
@@ -73746,7 +73776,7 @@ MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePa
|
||||
if (pFilePath == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
||||
config = ma_sound_config_init_2(pEngine);
|
||||
config.pFilePath = pFilePath;
|
||||
config.flags = flags;
|
||||
@@ -73763,7 +73793,7 @@ MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pF
|
||||
if (pFilePath == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
||||
config = ma_sound_config_init_2(pEngine);
|
||||
config.pFilePathW = pFilePath;
|
||||
config.flags = flags;
|
||||
|
||||
Reference in New Issue
Block a user