App-MHFS
view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ma_get_bytes_per_sample(format) * channels; }
/*
Converts a log level to a string.
*/
MA_API const char* ma_log_level_to_string(ma_uint32 logLevel);
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
DEVICE I/O
==========
This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc.
*************************************************************************************************************************************************************
************************************************************************************************************************************************************/
#ifndef MA_NO_DEVICE_IO
/* Some backends are only supported on certain platforms. */
#if defined(MA_WIN32)
#define MA_SUPPORT_WASAPI
#if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */
#define MA_SUPPORT_DSOUND
#define MA_SUPPORT_WINMM
#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_LINUX)
#if !defined(MA_ANDROID) /* ALSA is not supported on Android. */
#define MA_SUPPORT_ALSA
#endif
#endif
#if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_PULSEAUDIO
#define MA_SUPPORT_JACK
#endif
#if defined(MA_ANDROID)
#define MA_SUPPORT_AAUDIO
#define MA_SUPPORT_OPENSL
#endif
#if defined(__OpenBSD__) /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */
#define MA_SUPPORT_SNDIO /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_SUPPORT_AUDIO4 /* Only support audio(4) on platforms with known support. */
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__)
#define MA_SUPPORT_OSS /* Only support OSS on specific platforms with known support. */
#endif
#endif
#if defined(MA_APPLE)
#define MA_SUPPORT_COREAUDIO
#endif
#if defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_WEBAUDIO
#endif
/* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
#if !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_NULL
#endif
#if !defined(MA_NO_WASAPI) && defined(MA_SUPPORT_WASAPI)
#define MA_ENABLE_WASAPI
#endif
#if !defined(MA_NO_DSOUND) && defined(MA_SUPPORT_DSOUND)
#define MA_ENABLE_DSOUND
#endif
#if !defined(MA_NO_WINMM) && defined(MA_SUPPORT_WINMM)
#define MA_ENABLE_WINMM
#endif
#if !defined(MA_NO_ALSA) && defined(MA_SUPPORT_ALSA)
#define MA_ENABLE_ALSA
#endif
#if !defined(MA_NO_PULSEAUDIO) && defined(MA_SUPPORT_PULSEAUDIO)
#define MA_ENABLE_PULSEAUDIO
#endif
#if !defined(MA_NO_JACK) && defined(MA_SUPPORT_JACK)
#define MA_ENABLE_JACK
#endif
#if !defined(MA_NO_COREAUDIO) && defined(MA_SUPPORT_COREAUDIO)
#define MA_ENABLE_COREAUDIO
#endif
#if !defined(MA_NO_SNDIO) && defined(MA_SUPPORT_SNDIO)
#define MA_ENABLE_SNDIO
#endif
#if !defined(MA_NO_AUDIO4) && defined(MA_SUPPORT_AUDIO4)
#define MA_ENABLE_AUDIO4
#endif
#if !defined(MA_NO_OSS) && defined(MA_SUPPORT_OSS)
#define MA_ENABLE_OSS
#endif
#if !defined(MA_NO_AAUDIO) && defined(MA_SUPPORT_AAUDIO)
#define MA_ENABLE_AAUDIO
#endif
#if !defined(MA_NO_OPENSL) && defined(MA_SUPPORT_OPENSL)
#define MA_ENABLE_OPENSL
#endif
#if !defined(MA_NO_WEBAUDIO) && defined(MA_SUPPORT_WEBAUDIO)
#define MA_ENABLE_WEBAUDIO
#endif
#if !defined(MA_NO_NULL) && defined(MA_SUPPORT_NULL)
#define MA_ENABLE_NULL
#endif
#ifdef MA_SUPPORT_WASAPI
/* We need a IMMNotificationClient object for WASAPI. */
typedef struct
{
void* lpVtbl;
ma_uint32 counter;
ma_device* pDevice;
} ma_IMMNotificationClient;
#endif
/* Backend enums must be in priority order. */
typedef enum
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_result result;
MA_ASSERT(pContext != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDevice != NULL);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
/* No exclusive mode with the Core Audio backend for now. */
if (((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive) ||
((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive)) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
/* Capture needs to be initialized first. */
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_device_init_internal_data__coreaudio data;
data.formatIn = pConfig->capture.format;
data.channelsIn = pConfig->capture.channels;
data.sampleRateIn = pConfig->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap));
data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
data.shareMode = pConfig->capture.shareMode;
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
data.periodsIn = pConfig->periods;
data.registerStopEvent = MA_TRUE;
/* Need at least 3 periods for duplex. */
if (data.periodsIn < 3 && pConfig->deviceType == ma_device_type_duplex) {
data.periodsIn = 3;
}
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pConfig->capture.pDeviceID, &data, (void*)pDevice);
if (result != MA_SUCCESS) {
return result;
}
pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL);
#if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
#endif
pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
pDevice->capture.internalFormat = data.formatOut;
pDevice->capture.internalChannels = data.channelsOut;
pDevice->capture.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->capture.internalPeriods = data.periodsOut;
#if defined(MA_APPLE_DESKTOP)
/*
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.
*/
if (pConfig->capture.pDeviceID == NULL) {
ma_device__track__coreaudio(pDevice);
}
#endif
}
/* Playback. */
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_device_init_internal_data__coreaudio data;
data.formatIn = pConfig->playback.format;
data.channelsIn = pConfig->playback.channels;
data.sampleRateIn = pConfig->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap));
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
data.shareMode = pConfig->playback.shareMode;
/* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
if (pConfig->deviceType == ma_device_type_duplex) {
data.periodSizeInFramesIn = pDevice->capture.internalPeriodSizeInFrames;
data.periodsIn = pDevice->capture.internalPeriods;
data.registerStopEvent = MA_FALSE;
} else {
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
data.periodsIn = pConfig->periods;
data.registerStopEvent = MA_TRUE;
}
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data, (void*)pDevice);
if (result != MA_SUCCESS) {
if (pConfig->deviceType == ma_device_type_duplex) {
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
if (pDevice->coreaudio.pAudioBufferList) {
ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
}
}
return result;
}
pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL);
#if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
#endif
pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
pDevice->playback.internalFormat = data.formatOut;
pDevice->playback.internalChannels = data.channelsOut;
pDevice->playback.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->playback.internalPeriods = data.periodsOut;
#if defined(MA_APPLE_DESKTOP)
/*
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.
*/
if (pConfig->playback.pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pConfig->capture.pDeviceID != NULL)) {
ma_device__track__coreaudio(pDevice);
}
#endif
}
pDevice->coreaudio.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
pDevice->coreaudio.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
pDevice->coreaudio.originalPeriods = pConfig->periods;
/*
When stopping the device, a callback is called on another thread. We need to wait for this callback
before returning from ma_device_stop(). This event is used for this.
*/
ma_event_init(&pDevice->coreaudio.stopEvent);
/* Need a ring buffer for duplex mode. */
if (pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->coreaudio.duplexRB);
if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result);
}
/* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
{
ma_uint32 bufferSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
void* pBufferData;
ma_pcm_rb_acquire_write(&pDevice->coreaudio.duplexRB, &bufferSizeInFrames, &pBufferData);
{
MA_ZERO_MEMORY(pBufferData, bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
}
ma_pcm_rb_commit_write(&pDevice->coreaudio.duplexRB, bufferSizeInFrames, pBufferData);
}
}
/*
We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
differently on non-Desktop Apple platforms.
*/
#if defined(MA_APPLE_MOBILE)
pDevice->coreaudio.pRouteChangeHandler = (__bridge_retained void*)[[ma_router_change_handler alloc] init:pDevice];
#endif
return MA_SUCCESS;
}
static ma_result ma_device_start__coreaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
if (status != noErr) {
return ma_result_from_OSStatus(status);
}
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* Default periods. */
if (config.periods == 0) {
config.periods = MA_DEFAULT_PERIODS;
pDevice->usingDefaultPeriods = MA_TRUE;
}
/*
Must have at least 3 periods for full-duplex mode. The idea is that the playback and capture positions hang out in the middle period, with the surrounding
periods acting as a buffer in case the capture and playback devices get's slightly out of sync.
*/
if (config.deviceType == ma_device_type_duplex && config.periods < 3) {
config.periods = 3;
}
/* Default buffer size. */
if (config.periodSizeInMilliseconds == 0 && config.periodSizeInFrames == 0) {
config.periodSizeInMilliseconds = (config.performanceProfile == ma_performance_profile_low_latency) ? MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
pDevice->usingDefaultBufferSize = MA_TRUE;
}
MA_ASSERT(config.capture.channels <= MA_MAX_CHANNELS);
MA_ASSERT(config.playback.channels <= MA_MAX_CHANNELS);
pDevice->type = config.deviceType;
pDevice->sampleRate = config.sampleRate;
pDevice->resampling.algorithm = config.resampling.algorithm;
pDevice->resampling.linear.lpfOrder = config.resampling.linear.lpfOrder;
pDevice->resampling.speex.quality = config.resampling.speex.quality;
pDevice->capture.shareMode = config.capture.shareMode;
pDevice->capture.format = config.capture.format;
pDevice->capture.channels = config.capture.channels;
ma_channel_map_copy(pDevice->capture.channelMap, config.capture.channelMap, config.capture.channels);
pDevice->playback.shareMode = config.playback.shareMode;
pDevice->playback.format = config.playback.format;
pDevice->playback.channels = config.playback.channels;
ma_channel_map_copy(pDevice->playback.channelMap, config.playback.channelMap, config.playback.channels);
/* The internal format, channel count and sample rate can be modified by the backend. */
pDevice->capture.internalFormat = pDevice->capture.format;
pDevice->capture.internalChannels = pDevice->capture.channels;
pDevice->capture.internalSampleRate = pDevice->sampleRate;
ma_channel_map_copy(pDevice->capture.internalChannelMap, pDevice->capture.channelMap, pDevice->capture.channels);
pDevice->playback.internalFormat = pDevice->playback.format;
pDevice->playback.internalChannels = pDevice->playback.channels;
pDevice->playback.internalSampleRate = pDevice->sampleRate;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pDevice->playback.channelMap, pDevice->playback.channels);
result = ma_mutex_init(&pDevice->lock);
if (result != MA_SUCCESS) {
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result);
}
/*
When the device is started, the worker thread is the one that does the actual startup of the backend device. We
use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
Each of these semaphores is released internally by the worker thread when the work is completed. The start
semaphore is also used to wake up the worker thread.
*/
result = ma_event_init(&pDevice->wakeupEvent);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result);
}
result = ma_event_init(&pDevice->startEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result);
}
result = ma_event_init(&pDevice->stopEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result);
}
result = pContext->onDeviceInit(pContext, &config, pDevice);
if (result != MA_SUCCESS) {
return result;
}
ma_device__post_init_setup(pDevice, pConfig->deviceType);
/* If the backend did not fill out a name for the device, try a generic method. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->capture.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_capture, config.capture.pDeviceID, pDevice->capture.name, sizeof(pDevice->capture.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), (config.capture.pDeviceID == NULL) ? MA_DEFAULT_CAPTURE_DEVICE_NAME : "Capture Device", (size_t)-1);
}
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
if (pDevice->playback.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_playback, config.playback.pDeviceID, pDevice->playback.name, sizeof(pDevice->playback.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), (config.playback.pDeviceID == NULL) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1);
}
}
}
/* Some backends don't require the worker thread. */
if (!ma_context_is_backend_asynchronous(pContext)) {
/* The worker thread. */
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice);
if (result != MA_SUCCESS) {
ma_device_uninit(pDevice);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result);
}
( run in 0.651 second using v1.01-cache-2.11-cpan-0d23b851a93 )