App-MHFS
view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
|----------------------|
| MA_LOG_LEVEL_VERBOSE |
| MA_LOG_LEVEL_INFO |
| MA_LOG_LEVEL_WARNING |
| MA_LOG_LEVEL_ERROR |
|----------------------|
message (in)
The log message.
Remarks
-------
Do not modify the state of the device from inside the callback.
*/
typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message);
typedef enum
{
ma_device_type_playback = 1,
ma_device_type_capture = 2,
ma_device_type_duplex = ma_device_type_playback | ma_device_type_capture, /* 3 */
ma_device_type_loopback = 4
} ma_device_type;
typedef enum
{
ma_share_mode_shared = 0,
ma_share_mode_exclusive
} ma_share_mode;
/* iOS/tvOS/watchOS session categories. */
typedef enum
{
ma_ios_session_category_default = 0, /* AVAudioSessionCategoryPlayAndRecord with AVAudioSessionCategoryOptionDefaultToSpeaker. */
ma_ios_session_category_none, /* Leave the session category unchanged. */
ma_ios_session_category_ambient, /* AVAudioSessionCategoryAmbient */
ma_ios_session_category_solo_ambient, /* AVAudioSessionCategorySoloAmbient */
ma_ios_session_category_playback, /* AVAudioSessionCategoryPlayback */
ma_ios_session_category_record, /* AVAudioSessionCategoryRecord */
ma_ios_session_category_play_and_record, /* AVAudioSessionCategoryPlayAndRecord */
ma_ios_session_category_multi_route /* AVAudioSessionCategoryMultiRoute */
} ma_ios_session_category;
/* iOS/tvOS/watchOS session category options */
typedef enum
{
ma_ios_session_category_option_mix_with_others = 0x01, /* AVAudioSessionCategoryOptionMixWithOthers */
ma_ios_session_category_option_duck_others = 0x02, /* AVAudioSessionCategoryOptionDuckOthers */
ma_ios_session_category_option_allow_bluetooth = 0x04, /* AVAudioSessionCategoryOptionAllowBluetooth */
ma_ios_session_category_option_default_to_speaker = 0x08, /* AVAudioSessionCategoryOptionDefaultToSpeaker */
ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others = 0x11, /* AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers */
ma_ios_session_category_option_allow_bluetooth_a2dp = 0x20, /* AVAudioSessionCategoryOptionAllowBluetoothA2DP */
ma_ios_session_category_option_allow_air_play = 0x40, /* AVAudioSessionCategoryOptionAllowAirPlay */
} ma_ios_session_category_option;
typedef union
{
ma_int64 counter;
double counterD;
} ma_timer;
typedef union
{
wchar_t wasapi[64]; /* WASAPI uses a wchar_t string for identification. */
ma_uint8 dsound[16]; /* DirectSound uses a GUID for identification. */
/*UINT_PTR*/ ma_uint32 winmm; /* When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. */
char alsa[256]; /* ALSA uses a name string for identification. */
char pulse[256]; /* PulseAudio uses a name string for identification. */
int jack; /* JACK always uses default devices. */
char coreaudio[256]; /* Core Audio uses a string for identification. */
char sndio[256]; /* "snd/0", etc. */
char audio4[256]; /* "/dev/audio", etc. */
char oss[64]; /* "dev/dsp0", etc. "dev/dsp" for the default device. */
ma_int32 aaudio; /* AAudio uses a 32-bit integer for identification. */
ma_uint32 opensl; /* OpenSL|ES uses a 32-bit unsigned integer for identification. */
char webaudio[32]; /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */
int nullbackend; /* The null backend uses an integer for device IDs. */
} ma_device_id;
typedef struct
{
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
ma_device_id id;
char name[256];
/*
Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize
a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion
pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided
here mainly for informational purposes or in the rare case that someone might find it useful.
These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices().
*/
ma_uint32 formatCount;
ma_format formats[ma_format_count];
ma_uint32 minChannels;
ma_uint32 maxChannels;
ma_uint32 minSampleRate;
ma_uint32 maxSampleRate;
struct
{
ma_bool32 isDefault;
} _private;
} ma_device_info;
typedef struct
{
ma_device_type deviceType;
ma_uint32 sampleRate;
ma_uint32 periodSizeInFrames;
ma_uint32 periodSizeInMilliseconds;
ma_uint32 periods;
ma_performance_profile performanceProfile;
ma_bool32 noPreZeroedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
ma_bool32 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
ma_device_callback_proc dataCallback;
ma_stop_proc stopCallback;
void* pUserData;
struct
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
} sndio;
#endif
#ifdef MA_SUPPORT_AUDIO4
struct
{
int fdPlayback;
int fdCapture;
} audio4;
#endif
#ifdef MA_SUPPORT_OSS
struct
{
int fdPlayback;
int fdCapture;
} oss;
#endif
#ifdef MA_SUPPORT_AAUDIO
struct
{
/*AAudioStream**/ ma_ptr pStreamPlayback;
/*AAudioStream**/ ma_ptr pStreamCapture;
ma_pcm_rb duplexRB;
} aaudio;
#endif
#ifdef MA_SUPPORT_OPENSL
struct
{
/*SLObjectItf*/ ma_ptr pOutputMixObj;
/*SLOutputMixItf*/ ma_ptr pOutputMix;
/*SLObjectItf*/ ma_ptr pAudioPlayerObj;
/*SLPlayItf*/ ma_ptr pAudioPlayer;
/*SLObjectItf*/ ma_ptr pAudioRecorderObj;
/*SLRecordItf*/ ma_ptr pAudioRecorder;
/*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
/*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
ma_bool32 isDrainingCapture;
ma_bool32 isDrainingPlayback;
ma_uint32 currentBufferIndexPlayback;
ma_uint32 currentBufferIndexCapture;
ma_uint8* pBufferPlayback; /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
ma_uint8* pBufferCapture;
ma_pcm_rb duplexRB;
} opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
struct
{
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexCapture;
ma_pcm_rb duplexRB; /* In external capture format. */
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_uint32 operation;
ma_result operationResult;
ma_timer timer;
double priorRunTime;
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint64 lastProcessedFrameCapture;
ma_bool32 isStarted;
} null_device;
#endif
};
};
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#else
#pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#endif
/*
Initializes a `ma_context_config` object.
Return Value
------------
A `ma_context_config` initialized to defaults.
Remarks
-------
You must always use this to initialize the default state of the `ma_context_config` object. Not using this will result in your program breaking when miniaudio
is updated and new members are added to `ma_context_config`. It also sets logical defaults.
You can override members of the returned object by changing it's members directly.
See Also
--------
ma_context_init()
*/
MA_API ma_context_config ma_context_config_init(void);
/*
Initializes a context.
The context is used for selecting and initializing an appropriate backend and to represent the backend at a more global level than that of an individual
device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices.
Parameters
----------
backends (in, optional)
A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
backendCount (in, optional)
The number of items in `backend`. Ignored if `backend` is NULL.
pConfig (in, optional)
The context configuration.
pContext (in)
A pointer to the context object being initialized.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (pContext != NULL) {
pAllocationCallbacks = &pContext->allocationCallbacks;
}
pFormattedMessage = (char*)ma_malloc(formattedLen + 1, pAllocationCallbacks);
if (pFormattedMessage != NULL) {
/* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */
#if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */
vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args);
#else
vsprintf(pFormattedMessage, pFormat, args);
#endif
ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage);
ma_free(pFormattedMessage, pAllocationCallbacks);
}
}
#else
/* Can't do anything because we don't have a safe way of to emulate vsnprintf() without a manual solution. */
(void)pContext;
(void)pDevice;
(void)logLevel;
(void)pFormat;
(void)args;
#endif
}
#endif
}
MA_API void ma_post_log_messagef(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, ...)
{
va_list args;
va_start(args, pFormat);
{
ma_post_log_messagev(pContext, pDevice, logLevel, pFormat, args);
}
va_end(args);
}
/* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */
static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
{
ma_post_log_message(pContext, pDevice, logLevel, message);
return resultCode;
}
static ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
{
return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode);
}
/*******************************************************************************
Timing
*******************************************************************************/
#ifdef MA_WIN32
static LARGE_INTEGER g_ma_TimerFrequency = {{0}};
static void ma_timer_init(ma_timer* pTimer)
{
LARGE_INTEGER counter;
if (g_ma_TimerFrequency.QuadPart == 0) {
QueryPerformanceFrequency(&g_ma_TimerFrequency);
}
QueryPerformanceCounter(&counter);
pTimer->counter = counter.QuadPart;
}
static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
{
LARGE_INTEGER counter;
if (!QueryPerformanceCounter(&counter)) {
return 0;
}
return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart;
}
#elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
static ma_uint64 g_ma_TimerFrequency = 0;
static void ma_timer_init(ma_timer* pTimer)
{
mach_timebase_info_data_t baseTime;
mach_timebase_info(&baseTime);
g_ma_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer;
pTimer->counter = mach_absolute_time();
}
static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
{
ma_uint64 newTimeCounter = mach_absolute_time();
ma_uint64 oldTimeCounter = pTimer->counter;
return (newTimeCounter - oldTimeCounter) / g_ma_TimerFrequency;
}
#elif defined(MA_EMSCRIPTEN)
static MA_INLINE void ma_timer_init(ma_timer* pTimer)
{
pTimer->counterD = emscripten_get_now();
}
static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer)
{
return (emscripten_get_now() - pTimer->counterD) / 1000; /* Emscripten is in milliseconds. */
}
#else
#if _POSIX_C_SOURCE >= 199309L
#if defined(CLOCK_MONOTONIC)
#define MA_CLOCK_ID CLOCK_MONOTONIC
#else
#define MA_CLOCK_ID CLOCK_REALTIME
#endif
static void ma_timer_init(ma_timer* pTimer)
{
struct timespec newTime;
clock_gettime(MA_CLOCK_ID, &newTime);
pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
}
static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
{
ma_uint64 newTimeCounter;
ma_uint64 oldTimeCounter;
struct timespec newTime;
clock_gettime(MA_CLOCK_ID, &newTime);
newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
oldTimeCounter = pTimer->counter;
return (newTimeCounter - oldTimeCounter) / 1000000000.0;
}
#else
static void ma_timer_init(ma_timer* pTimer)
{
struct timeval newTime;
gettimeofday(&newTime, NULL);
pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
}
static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
{
ma_uint64 newTimeCounter;
ma_uint64 oldTimeCounter;
struct timeval newTime;
gettimeofday(&newTime, NULL);
newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
oldTimeCounter = pTimer->counter;
return (newTimeCounter - oldTimeCounter) / 1000000.0;
}
#endif
#endif
/*******************************************************************************
Dynamic Linking
*******************************************************************************/
MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename)
{
ma_handle handle;
#if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE
if (pContext != NULL) {
char message[256];
ma_strappend(message, sizeof(message), "Loading library: ", filename);
ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
}
#endif
#ifdef _WIN32
#ifdef MA_WIN32_DESKTOP
handle = (ma_handle)LoadLibraryA(filename);
#else
/* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */
WCHAR filenameW[4096];
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) {
handle = NULL;
} else {
handle = (ma_handle)LoadPackagedLibrary(filenameW, 0);
}
#endif
#else
handle = (ma_handle)dlopen(filename, RTLD_NOW);
#endif
/*
I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority
backend is a deliberate design choice. Instead I'm logging it as an informational message.
*/
#if MA_LOG_LEVEL >= MA_LOG_LEVEL_INFO
if (handle == NULL) {
char message[256];
ma_strappend(message, sizeof(message), "Failed to load library: ", filename);
ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, message);
}
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
data.pDeviceID = pDeviceID;
data.pName = pName;
data.nameBufferSize = nameBufferSize;
data.foundDevice = MA_FALSE;
result = ma_context_enumerate_devices(pContext, ma_context__try_get_device_name_by_id__enum_callback, &data);
if (result != MA_SUCCESS) {
return result;
}
if (!data.foundDevice) {
return MA_NO_DEVICE;
} else {
return MA_SUCCESS;
}
}
MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */
{
ma_uint32 i;
for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) {
if (g_maFormatPriorities[i] == format) {
return i;
}
}
/* Getting here means the format could not be found or is equal to ma_format_unknown. */
return (ma_uint32)-1;
}
static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType);
/*******************************************************************************
Null Backend
*******************************************************************************/
#ifdef MA_HAS_NULL
#define MA_DEVICE_OP_NONE__NULL 0
#define MA_DEVICE_OP_START__NULL 1
#define MA_DEVICE_OP_SUSPEND__NULL 2
#define MA_DEVICE_OP_KILL__NULL 3
static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
for (;;) { /* Keep the thread alive until the device is uninitialized. */
/* Wait for an operation to be requested. */
ma_event_wait(&pDevice->null_device.operationEvent);
/* At this point an event should have been triggered. */
/* Starting the device needs to put the thread into a loop. */
if (pDevice->null_device.operation == MA_DEVICE_OP_START__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
/* Reset the timer just in case. */
ma_timer_init(&pDevice->null_device.timer);
/* Keep looping until an operation has been requested. */
while (pDevice->null_device.operation != MA_DEVICE_OP_NONE__NULL && pDevice->null_device.operation != MA_DEVICE_OP_START__NULL) {
ma_sleep(10); /* Don't hog the CPU. */
}
/* Getting here means a suspend or kill operation has been requested. */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue;
}
/* Suspending the device means we need to stop the timer and just continue the loop. */
if (pDevice->null_device.operation == MA_DEVICE_OP_SUSPEND__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
/* We need to add the current run time to the prior run time, then reset the timer. */
pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
ma_timer_init(&pDevice->null_device.timer);
/* We're done. */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue;
}
/* Killing the device means we need to get out of this loop so that this thread can terminate. */
if (pDevice->null_device.operation == MA_DEVICE_OP_KILL__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
break;
}
/* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
if (pDevice->null_device.operation == MA_DEVICE_OP_NONE__NULL) {
MA_ASSERT(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, (c89atomic_uint32)MA_INVALID_OPERATION);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue; /* Continue the loop. Don't terminate. */
}
}
return (ma_thread_result)0;
}
static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
{
c89atomic_exchange_32(&pDevice->null_device.operation, operation);
if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
return MA_ERROR;
}
if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) {
return MA_ERROR;
}
return pDevice->null_device.operationResult;
}
static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice)
{
ma_uint32 internalSampleRate;
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
internalSampleRate = pDevice->capture.internalSampleRate;
} else {
internalSampleRate = pDevice->playback.internalSampleRate;
}
return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate);
}
static ma_bool32 ma_context_is_device_id_equal__null(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pID0 != NULL);
MA_ASSERT(pID1 != NULL);
(void)pContext;
return pID0->nullbackend == pID1->nullbackend;
}
static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
ma_bool32 cbResult = MA_TRUE;
MA_ASSERT(pContext != NULL);
MA_ASSERT(callback != NULL);
/* Playback. */
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1);
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
}
/* Capture. */
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1);
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
}
return MA_SUCCESS;
}
static ma_result ma_context_get_device_info__null(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
{
ma_uint32 iFormat;
MA_ASSERT(pContext != NULL);
if (pDeviceID != NULL && pDeviceID->nullbackend != 0) {
return MA_NO_DEVICE; /* Don't know the device. */
}
/* Name / Description */
if (deviceType == ma_device_type_playback) {
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1);
}
/* Support everything on the null backend. */
pDeviceInfo->formatCount = ma_format_count - 1; /* Minus one because we don't want to include ma_format_unknown. */
for (iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) {
pDeviceInfo->formats[iFormat] = (ma_format)(iFormat + 1); /* +1 to skip over ma_format_unknown. */
}
pDeviceInfo->minChannels = 1;
pDeviceInfo->maxChannels = MA_MAX_CHANNELS;
pDeviceInfo->minSampleRate = MA_SAMPLE_RATE_8000;
pDeviceInfo->maxSampleRate = MA_SAMPLE_RATE_384000;
(void)pContext;
(void)shareMode;
return MA_SUCCESS;
}
static void ma_device_uninit__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/* Keep it clean and wait for the device thread to finish before returning. */
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL);
/* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
ma_event_uninit(&pDevice->null_device.operationEvent);
}
static ma_result ma_device_init__null(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
{
ma_result result;
ma_uint32 periodSizeInFrames;
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->null_device);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
periodSizeInFrames = pConfig->periodSizeInFrames;
if (periodSizeInFrames == 0) {
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pConfig->sampleRate);
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "NULL Capture Device", (size_t)-1);
pDevice->capture.internalFormat = pConfig->capture.format;
pDevice->capture.internalChannels = pConfig->capture.channels;
ma_channel_map_copy(pDevice->capture.internalChannelMap, pConfig->capture.channelMap, ma_min(pConfig->capture.channels, MA_MAX_CHANNELS));
pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->capture.internalPeriods = pConfig->periods;
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1);
pDevice->playback.internalFormat = pConfig->playback.format;
pDevice->playback.internalChannels = pConfig->playback.channels;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pConfig->playback.channelMap, ma_min(pConfig->playback.channels, MA_MAX_CHANNELS));
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->playback.internalPeriods = pConfig->periods;
}
/*
In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the
first period is "written" to it, and then stopped in ma_device_stop__null().
*/
result = ma_event_init(&pDevice->null_device.operationEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_event_init(&pDevice->null_device.operationCompletionEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, 0, ma_device_thread__null, pDevice);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static ma_result ma_device_start__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL);
c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE);
return MA_SUCCESS;
}
static ma_result ma_device_stop__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL);
c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE);
return MA_SUCCESS;
}
static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{
ma_result result = MA_SUCCESS;
ma_uint32 totalPCMFramesProcessed;
ma_bool32 wasStartedOnEntry;
if (pFramesWritten != NULL) {
*pFramesWritten = 0;
}
wasStartedOnEntry = pDevice->null_device.isStarted;
/* Keep going until everything has been read. */
totalPCMFramesProcessed = 0;
while (totalPCMFramesProcessed < frameCount) {
ma_uint64 targetFrame;
/* If there are any frames remaining in the current period, consume those first. */
if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) {
ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
bqConfig = ma_hishelf2__get_biquad_config(pConfig);
result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
}
static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2* pFilter, float* pFrameOut, const float* pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
}
MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
{
if (pFilter == NULL) {
return MA_INVALID_ARGS;
}
return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
}
MA_API ma_uint32 ma_hishelf2_get_latency(ma_hishelf2* pFilter)
{
if (pFilter == NULL) {
return 0;
}
return ma_biquad_get_latency(&pFilter->bq);
}
/**************************************************************************************************************************************************************
Resampling
**************************************************************************************************************************************************************/
MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
{
ma_linear_resampler_config config;
MA_ZERO_OBJECT(&config);
config.format = format;
config.channels = channels;
config.sampleRateIn = sampleRateIn;
config.sampleRateOut = sampleRateOut;
config.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
config.lpfNyquistFactor = 1;
return config;
}
static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* pResampler, ma_uint32 oldSampleRateOut, ma_uint32 newSampleRateOut)
{
/*
So what's happening here? Basically we need to adjust the fractional component of the time advance based on the new rate. The old time advance will
be based on the old sample rate, but we are needing to adjust it to that it's based on the new sample rate.
*/
ma_uint32 oldRateTimeWhole = pResampler->inTimeFrac / oldSampleRateOut; /* <-- This should almost never be anything other than 0, but leaving it here to make this more general and robust just in case. */
ma_uint32 oldRateTimeFract = pResampler->inTimeFrac % oldSampleRateOut;
pResampler->inTimeFrac =
(oldRateTimeWhole * newSampleRateOut) +
((oldRateTimeFract * newSampleRateOut) / oldSampleRateOut);
/* Make sure the fractional part is less than the output sample rate. */
pResampler->inTimeInt += pResampler->inTimeFrac / pResampler->config.sampleRateOut;
pResampler->inTimeFrac = pResampler->inTimeFrac % pResampler->config.sampleRateOut;
}
static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized)
{
ma_result result;
ma_uint32 gcf;
ma_uint32 lpfSampleRate;
double lpfCutoffFrequency;
ma_lpf_config lpfConfig;
ma_uint32 oldSampleRateOut; /* Required for adjusting time advance down the bottom. */
if (pResampler == NULL) {
return MA_INVALID_ARGS;
}
if (sampleRateIn == 0 || sampleRateOut == 0) {
return MA_INVALID_ARGS;
}
oldSampleRateOut = pResampler->config.sampleRateOut;
pResampler->config.sampleRateIn = sampleRateIn;
pResampler->config.sampleRateOut = sampleRateOut;
/* Simplify the sample rate. */
gcf = ma_gcf_u32(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut);
pResampler->config.sampleRateIn /= gcf;
pResampler->config.sampleRateOut /= gcf;
/* Always initialize the low-pass filter, even when the order is 0. */
if (pResampler->config.lpfOrder > MA_MAX_FILTER_ORDER) {
return MA_INVALID_ARGS;
}
lpfSampleRate = (ma_uint32)(ma_max(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut));
lpfCutoffFrequency = ( double)(ma_min(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut) * 0.5 * pResampler->config.lpfNyquistFactor);
lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder);
/*
If the resampler is alreay initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames
getting cleared. Instead we re-initialize the filter which will maintain any cached frames.
*/
if (isResamplerAlreadyInitialized) {
result = ma_lpf_reinit(&lpfConfig, &pResampler->lpf);
} else {
result = ma_lpf_init(&lpfConfig, &pResampler->lpf);
}
if (result != MA_SUCCESS) {
return result;
}
pResampler->inAdvanceInt = pResampler->config.sampleRateIn / pResampler->config.sampleRateOut;
pResampler->inAdvanceFrac = pResampler->config.sampleRateIn % pResampler->config.sampleRateOut;
/* Our timer was based on the old rate. We need to adjust it so that it's based on the new rate. */
ma_linear_resampler_adjust_timer_for_new_rate(pResampler, oldSampleRateOut, pResampler->config.sampleRateOut);
return MA_SUCCESS;
}
MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler)
{
ma_result result;
if (pResampler == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pResampler);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
pResampler->config = *pConfig;
/* Setting the rate will set up the filter and time advances for us. */
result = ma_linear_resampler_set_rate_internal(pResampler, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE);
if (result != MA_SUCCESS) {
return result;
}
pResampler->inTimeInt = 1; /* Set this to one to force an input sample to always be loaded for the first output frame. */
pResampler->inTimeFrac = 0;
return MA_SUCCESS;
}
MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler)
{
if (pResampler == NULL) {
return;
}
}
static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift)
{
ma_int32 b;
ma_int32 c;
ma_int32 r;
MA_ASSERT(a <= (1<<shift));
b = x * ((1<<shift) - a);
c = y * a;
r = b + c;
return (ma_int16)(r >> shift);
}
static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* pFrameOut)
{
( run in 2.845 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )