view release on metacpan or search on metacpan
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
engineConfig = ma_engine_config_init();
engineConfig.pResourceManager = &myCustomResourceManager; // <-- Initialized as some earlier stage.
result = ma_engine_init(&engineConfig, &engine);
if (result != MA_SUCCESS) {
return result;
}
```
This creates an engine instance using a custom config. In this particular example it's showing how
you can specify a custom resource manager rather than having the engine initialize one internally.
This is particularly useful if you want to have multiple engine's share the same resource manager.
The engine must be uninitialized with `ma_engine_uninit()` when it's no longer needed.
By default the engine will be started, but nothing will be playing because no sounds have been
initialized. The easiest but least flexible way of playing a sound is like so:
```c
ma_engine_play_sound(&engine, "my_sound.wav", NULL);
```
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
initialize a sound:
```c
ma_result result;
ma_sound sound;
result = ma_sound_init_from_file(&engine, "my_sound.wav", 0, NULL, NULL, &sound);
if (result != MA_SUCCESS) {
return result;
}
ma_sound_start(&sound);
```
This returns a `ma_sound` object which represents a single instance of the specified sound file. If
you want to play the same file multiple times simultaneously, you need to create one sound for each
instance.
Sounds should be uninitialized with `ma_sound_uninit()`.
Sounds are not started by default. Start a sound with `ma_sound_start()` and stop it with
`ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use
`ma_sound_seek_to_pcm_frames(&sound, 0)` to seek back to the start of a sound. By default, starting
and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound
the be started and/or stopped at a specific time. This can be done with the following functions:
```c
ma_sound_set_start_time_in_pcm_frames()
ma_sound_set_start_time_in_milliseconds()
ma_sound_set_stop_time_in_pcm_frames()
ma_sound_set_stop_time_in_milliseconds()
```
The start/stop time needs to be specified based on the absolute timer which is controlled by the
engine. The current global time time in PCM frames can be retrieved with `ma_engine_get_time()`.
The engine's global time can be changed with `ma_engine_set_time()` for synchronization purposes if
required. Note that scheduling a start time still requires an explicit call to `ma_sound_start()`
before anything will play:
```c
ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2);
ma_sound_start(&sound);
```
The third parameter of `ma_sound_init_from_file()` is a set of flags that control how the sound be
loaded and a few options on which features should be enabled for that sound. By default, the sound
is synchronously loaded fully into memory straight from the file system without any kind of
decoding. If you want to decode the sound before storing it in memory, you need to specify the
`MA_SOUND_FLAG_DECODE` flag. This is useful if you want to incur the cost of decoding at an earlier
stage, such as a loading stage. Without this option, decoding will happen dynamically at mixing
time which might be too expensive on the audio thread.
If you want to load the sound asynchronously, you can specify the `MA_SOUND_FLAG_ASYNC` flag. This
will result in `ma_sound_init_from_file()` returning quickly, but the sound will not start playing
until the sound has had some audio decoded.
The fourth parameter is a pointer to sound group. A sound group is used as a mechanism to organise
sounds into groups which have their own effect processing and volume control. An example is a game
which might have separate groups for sfx, voice and music. Each of these groups have their own
independent volume control. Use `ma_sound_group_init()` or `ma_sound_group_init_ex()` to initialize
a sound group.
Sounds and sound groups are nodes in the engine's node graph and can be plugged into any `ma_node`
API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex
effect chains.
A sound can have it's volume changed with `ma_sound_set_volume()`. If you prefer decibel volume
control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear.
Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know
a sound will never have it's pitch changed with `ma_sound_set_pitch()` or via the doppler effect,
you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization.
By default, sounds and sound groups have spatialization enabled. If you don't ever want to
spatialize your sounds, initialize the sound with the `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. The
spatialization model is fairly simple and is roughly on feature parity with OpenAL. HRTF and
environmental occlusion are not currently supported, but planned for the future. The supported
features include:
* Sound and listener positioning and orientation with cones
* Attenuation models: none, inverse, linear and exponential
* Doppler effect
Sounds can be faded in and out with `ma_sound_set_fade_in_pcm_frames()`.
To check if a sound is currently playing, you can use `ma_sound_is_playing()`. To check if a sound
is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled with
`ma_sound_set_looping()`. Use `ma_sound_is_looping()` to check whether or not the sound is looping.
2. Building
===========
miniaudio should work cleanly out of the box without the need to download or install any
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
Both the input and output frames must be in the format specified in the config when the resampler was initilized.
On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that
were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use
ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames.
On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole
input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames
you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead.
If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of
output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input
frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be
processed. In this case, any internal filter state will be updated as if zeroes were passed in.
It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL.
It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
*/
MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
/*
Sets the input and output sample sample rate.
*/
MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
/*
Sets the input and output sample rate as a ratio.
The ration is in/out.
*/
MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio);
/*
Retrieves the latency introduced by the resampler in input frames.
*/
MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler);
/*
Retrieves the latency introduced by the resampler in output frames.
*/
MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler);
/*
Calculates the number of whole input frames that would need to be read from the client in order to output the specified
number of output frames.
The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
read from the input buffer in order to output the specified number of output frames.
*/
MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount);
/*
Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
input frames.
*/
MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount);
/*
Resets the resampler's timer and clears it's internal cache.
*/
MA_API ma_result ma_resampler_reset(ma_resampler* pResampler);
/**************************************************************************************************************************************************************
Channel Conversion
**************************************************************************************************************************************************************/
typedef enum
{
ma_channel_conversion_path_unknown,
ma_channel_conversion_path_passthrough,
ma_channel_conversion_path_mono_out, /* Converting to mono. */
ma_channel_conversion_path_mono_in, /* Converting from mono. */
ma_channel_conversion_path_shuffle, /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */
ma_channel_conversion_path_weights /* Blended based on weights. */
} ma_channel_conversion_path;
typedef enum
{
ma_mono_expansion_mode_duplicate = 0, /* The default. */
ma_mono_expansion_mode_average, /* Average the mono channel across all channels. */
ma_mono_expansion_mode_stereo_only, /* Duplicate to the left and right channels only and ignore the others. */
ma_mono_expansion_mode_default = ma_mono_expansion_mode_duplicate
} ma_mono_expansion_mode;
typedef struct
{
ma_format format;
ma_uint32 channelsIn;
ma_uint32 channelsOut;
const ma_channel* pChannelMapIn;
const ma_channel* pChannelMapOut;
ma_channel_mix_mode mixingMode;
float** ppWeights; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
} ma_channel_converter_config;
MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode);
typedef struct
{
ma_format format;
ma_uint32 channelsIn;
ma_uint32 channelsOut;
ma_channel_mix_mode mixingMode;
ma_channel_conversion_path conversionPath;
ma_channel* pChannelMapIn;
ma_channel* pChannelMapOut;
ma_uint8* pShuffleTable; /* Indexed by output channel index. */
union
{
float** f32;
ma_int32** s16;
} weights; /* [in][out] */
/* Memory management. */
void* _pHeap;
ma_bool32 _ownsHeap;
} ma_channel_converter;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
/* OpenSL recording presets. */
typedef enum
{
ma_opensl_recording_preset_default = 0, /* Leaves the input preset unset. */
ma_opensl_recording_preset_generic, /* SL_ANDROID_RECORDING_PRESET_GENERIC */
ma_opensl_recording_preset_camcorder, /* SL_ANDROID_RECORDING_PRESET_CAMCORDER */
ma_opensl_recording_preset_voice_recognition, /* SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION */
ma_opensl_recording_preset_voice_communication, /* SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION */
ma_opensl_recording_preset_voice_unprocessed /* SL_ANDROID_RECORDING_PRESET_UNPROCESSED */
} ma_opensl_recording_preset;
/* AAudio usage types. */
typedef enum
{
ma_aaudio_usage_default = 0, /* Leaves the usage type unset. */
ma_aaudio_usage_announcement, /* AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT */
ma_aaudio_usage_emergency, /* AAUDIO_SYSTEM_USAGE_EMERGENCY */
ma_aaudio_usage_safety, /* AAUDIO_SYSTEM_USAGE_SAFETY */
ma_aaudio_usage_vehicle_status, /* AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS */
ma_aaudio_usage_alarm, /* AAUDIO_USAGE_ALARM */
ma_aaudio_usage_assistance_accessibility, /* AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY */
ma_aaudio_usage_assistance_navigation_guidance, /* AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */
ma_aaudio_usage_assistance_sonification, /* AAUDIO_USAGE_ASSISTANCE_SONIFICATION */
ma_aaudio_usage_assitant, /* AAUDIO_USAGE_ASSISTANT */
ma_aaudio_usage_game, /* AAUDIO_USAGE_GAME */
ma_aaudio_usage_media, /* AAUDIO_USAGE_MEDIA */
ma_aaudio_usage_notification, /* AAUDIO_USAGE_NOTIFICATION */
ma_aaudio_usage_notification_event, /* AAUDIO_USAGE_NOTIFICATION_EVENT */
ma_aaudio_usage_notification_ringtone, /* AAUDIO_USAGE_NOTIFICATION_RINGTONE */
ma_aaudio_usage_voice_communication, /* AAUDIO_USAGE_VOICE_COMMUNICATION */
ma_aaudio_usage_voice_communication_signalling /* AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING */
} ma_aaudio_usage;
/* AAudio content types. */
typedef enum
{
ma_aaudio_content_type_default = 0, /* Leaves the content type unset. */
ma_aaudio_content_type_movie, /* AAUDIO_CONTENT_TYPE_MOVIE */
ma_aaudio_content_type_music, /* AAUDIO_CONTENT_TYPE_MUSIC */
ma_aaudio_content_type_sonification, /* AAUDIO_CONTENT_TYPE_SONIFICATION */
ma_aaudio_content_type_speech /* AAUDIO_CONTENT_TYPE_SPEECH */
} ma_aaudio_content_type;
/* AAudio input presets. */
typedef enum
{
ma_aaudio_input_preset_default = 0, /* Leaves the input preset unset. */
ma_aaudio_input_preset_generic, /* AAUDIO_INPUT_PRESET_GENERIC */
ma_aaudio_input_preset_camcorder, /* AAUDIO_INPUT_PRESET_CAMCORDER */
ma_aaudio_input_preset_unprocessed, /* AAUDIO_INPUT_PRESET_UNPROCESSED */
ma_aaudio_input_preset_voice_recognition, /* AAUDIO_INPUT_PRESET_VOICE_RECOGNITION */
ma_aaudio_input_preset_voice_communication, /* AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION */
ma_aaudio_input_preset_voice_performance /* AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE */
} ma_aaudio_input_preset;
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. */
union
{
int i;
char s[256];
void* p;
} custom; /* The custom backend could be anything. Give them a few options. */
int nullbackend; /* The null backend uses an integer for device IDs. */
} ma_device_id;
typedef struct ma_context_config ma_context_config;
typedef struct ma_device_config ma_device_config;
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[MA_MAX_DEVICE_NAME_LENGTH + 1]; /* +1 for null terminator. */
ma_bool32 isDefault;
ma_uint32 nativeDataFormatCount;
struct
{
ma_format format; /* Sample format. If set to ma_format_unknown, all sample formats are supported. */
ma_uint32 channels; /* If set to 0, all channels are supported. */
ma_uint32 sampleRate; /* If set to 0, all sample rates are supported. */
ma_uint32 flags; /* A combination of MA_DATA_FORMAT_FLAG_* flags. */
} nativeDataFormats[/*ma_format_count * ma_standard_sample_rate_count * MA_MAX_CHANNELS*/ 64]; /* Not sure how big to make this. There can be *many* permutations for virtual devices which can support anything. */
} ma_device_info;
struct ma_device_config
{
ma_device_type deviceType;
ma_uint32 sampleRate;
ma_uint32 periodSizeInFrames;
ma_uint32 periodSizeInMilliseconds;
ma_uint32 periods;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#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_aaudio_usage usage;
ma_aaudio_content_type contentType;
ma_aaudio_input_preset inputPreset;
ma_bool32 noAutoStartAfterReroute;
} 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;
} 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;
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_semaphore operationSemaphore;
ma_uint32 operation;
ma_result operationResult;
ma_timer timer;
double priorRunTime;
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint64 lastProcessedFrameCapture;
MA_ATOMIC(4, ma_bool32) isStarted; /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */
} null_device;
#endif
};
};
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
#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_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
case MA_DSERR_ALLOCATED: return MA_ALREADY_IN_USE;
case MA_DSERR_CONTROLUNAVAIL: return MA_INVALID_OPERATION;
/*case MA_DSERR_INVALIDPARAM: return MA_INVALID_ARGS;*/ /* E_INVALIDARG */
case MA_DSERR_INVALIDCALL: return MA_INVALID_OPERATION;
/*case MA_DSERR_GENERIC: return MA_ERROR;*/ /* E_FAIL */
case MA_DSERR_PRIOLEVELNEEDED: return MA_INVALID_OPERATION;
/*case MA_DSERR_OUTOFMEMORY: return MA_OUT_OF_MEMORY;*/ /* E_OUTOFMEMORY */
case MA_DSERR_BADFORMAT: return MA_FORMAT_NOT_SUPPORTED;
/*case MA_DSERR_UNSUPPORTED: return MA_NOT_IMPLEMENTED;*/ /* E_NOTIMPL */
case MA_DSERR_NODRIVER: return MA_FAILED_TO_INIT_BACKEND;
case MA_DSERR_ALREADYINITIALIZED: return MA_DEVICE_ALREADY_INITIALIZED;
case MA_DSERR_NOAGGREGATION: return MA_ERROR;
case MA_DSERR_BUFFERLOST: return MA_UNAVAILABLE;
case MA_DSERR_OTHERAPPHASPRIO: return MA_ACCESS_DENIED;
case MA_DSERR_UNINITIALIZED: return MA_DEVICE_NOT_INITIALIZED;
/*case MA_DSERR_NOINTERFACE: return MA_API_NOT_FOUND;*/ /* E_NOINTERFACE */
/*case MA_DSERR_ACCESSDENIED: return MA_ACCESS_DENIED;*/ /* E_ACCESSDENIED */
case MA_DSERR_BUFFERTOOSMALL: return MA_NO_SPACE;
case MA_DSERR_DS8_REQUIRED: return MA_INVALID_OPERATION;
case MA_DSERR_SENDLOOP: return MA_DEADLOCK;
case MA_DSERR_BADSENDBUFFERGUID: return MA_INVALID_ARGS;
case MA_DSERR_OBJECTNOTFOUND: return MA_NO_DEVICE;
case MA_DSERR_FXUNAVAILABLE: return MA_UNAVAILABLE;
default: return MA_ERROR;
}
}
typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit);
typedef void (WINAPI * MA_PFN_CoUninitialize)(void);
typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
typedef void (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv);
typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar);
typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax);
typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void);
typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void);
#if defined(MA_WIN32_DESKTOP)
/* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */
typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey);
typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
#endif /* MA_WIN32_DESKTOP */
#endif /* MA_WIN32 */
#define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device"
#define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device"
/*******************************************************************************
Timing
*******************************************************************************/
#ifdef MA_WIN32
static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's 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;
}
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 defined(_POSIX_C_SOURCE) && _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;
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename);
#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 (handle == NULL) {
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename);
}
(void)pContext; /* It's possible for pContext to be unused. */
return handle;
}
MA_API void ma_dlclose(ma_context* pContext, ma_handle handle)
{
#ifdef _WIN32
FreeLibrary((HMODULE)handle);
#else
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
framesToWriteThisIteration = playbackDeviceDataCapInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
/* Make sure we don't get stuck in the inner loop. */
if (framesProcessed == 0) {
break;
}
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* Should never get here. */
default: break;
}
}
return result;
}
/*******************************************************************************
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. */
ma_uint32 operation;
/* Wait for an operation to be requested. */
ma_event_wait(&pDevice->null_device.operationEvent);
/* At this point an event should have been triggered. */
operation = pDevice->null_device.operation;
/* Starting the device needs to put the thread into a loop. */
if (operation == MA_DEVICE_OP_START__NULL) {
/* Reset the timer just in case. */
ma_timer_init(&pDevice->null_device.timer);
/* Getting here means a suspend or kill operation has been requested. */
pDevice->null_device.operationResult = MA_SUCCESS;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
continue;
}
/* Suspending the device means we need to stop the timer and just continue the loop. */
if (operation == MA_DEVICE_OP_SUSPEND__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. */
pDevice->null_device.operationResult = MA_SUCCESS;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
continue;
}
/* Killing the device means we need to get out of this loop so that this thread can terminate. */
if (operation == MA_DEVICE_OP_KILL__NULL) {
pDevice->null_device.operationResult = MA_SUCCESS;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
break;
}
/* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
if (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). */
pDevice->null_device.operationResult = MA_INVALID_OPERATION;
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
ma_semaphore_release(&pDevice->null_device.operationSemaphore);
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)
{
ma_result result;
/*
TODO: Need to review this and consider just using mutual exclusion. I think the original motivation
for this was to just post the event to a queue and return immediately, but that has since changed
and now this function is synchronous. I think this can be simplified to just use a mutex.
*/
/*
The first thing to do is wait for an operation slot to become available. We only have a single slot for this, but we could extend this later
to support queing of operations.
*/
result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore);
if (result != MA_SUCCESS) {
return result; /* Failed to wait for the event. */
}
/*
When we get here it means the background thread is not referencing the operation code and it can be changed. After changing this we need to
signal an event to the worker thread to let it know that it can start work.
*/
pDevice->null_device.operation = operation;
/* Once the operation code has been set, the worker thread can start work. */
if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
return MA_ERROR;
}
/* We want everything to be synchronous so we're going to wait for the worker thread to complete it's operation. */
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_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);
deviceInfo.isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */
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);
deviceInfo.isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
}
(void)cbResult; /* Silence a static analysis warning. */
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_device_info* pDeviceInfo)
{
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);
}
pDeviceInfo->isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */
/* Support everything on the null backend. */
pDeviceInfo->nativeDataFormats[0].format = ma_format_unknown;
pDeviceInfo->nativeDataFormats[0].channels = 0;
pDeviceInfo->nativeDataFormats[0].sampleRate = 0;
pDeviceInfo->nativeDataFormats[0].flags = 0;
pDeviceInfo->nativeDataFormatCount = 1;
(void)pContext;
return MA_SUCCESS;
}
static ma_result 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);
/* Wait for the thread to finish before continuing. */
ma_thread_wait(&pDevice->null_device.deviceThread);
/* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
ma_semaphore_uninit(&pDevice->null_device.operationSemaphore);
ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
ma_event_uninit(&pDevice->null_device.operationEvent);
return MA_SUCCESS;
}
static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
ma_result result;
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->null_device);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
/* The null backend supports everything exactly as we specify it. */
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
pDescriptorCapture->format = (pDescriptorCapture->format != ma_format_unknown) ? pDescriptorCapture->format : MA_DEFAULT_FORMAT;
pDescriptorCapture->channels = (pDescriptorCapture->channels != 0) ? pDescriptorCapture->channels : MA_DEFAULT_CHANNELS;
pDescriptorCapture->sampleRate = (pDescriptorCapture->sampleRate != 0) ? pDescriptorCapture->sampleRate : MA_DEFAULT_SAMPLE_RATE;
if (pDescriptorCapture->channelMap[0] == MA_CHANNEL_NONE) {
ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
}
pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
pDescriptorPlayback->format = (pDescriptorPlayback->format != ma_format_unknown) ? pDescriptorPlayback->format : MA_DEFAULT_FORMAT;
pDescriptorPlayback->channels = (pDescriptorPlayback->channels != 0) ? pDescriptorPlayback->channels : MA_DEFAULT_CHANNELS;
pDescriptorPlayback->sampleRate = (pDescriptorPlayback->sampleRate != 0) ? pDescriptorPlayback->sampleRate : MA_DEFAULT_SAMPLE_RATE;
if (pDescriptorPlayback->channelMap[0] == MA_CHANNEL_NONE) {
ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorPlayback->channels);
}
pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
}
/*
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_semaphore_init(1, &pDevice->null_device.operationSemaphore); /* <-- It's important that the initial value is set to 1. */
if (result != MA_SUCCESS) {
return result;
}
result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice, &pDevice->pContext->allocationCallbacks);
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 = c89atomic_load_32(&pDevice->null_device.isStarted);
/* Keep going until everything has been read. */
totalPCMFramesProcessed = 0;
while (totalPCMFramesProcessed < frameCount) {
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
}
if (heapSizeInBytes > 0) {
pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
if (pHeap == NULL) {
return MA_OUT_OF_MEMORY;
}
} else {
pHeap = NULL;
}
result = ma_gainer_init_preallocated(pConfig, pHeap, pGainer);
if (result != MA_SUCCESS) {
ma_free(pHeap, pAllocationCallbacks);
return result;
}
pGainer->_ownsHeap = MA_TRUE;
return MA_SUCCESS;
}
MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pGainer == NULL) {
return;
}
if (pGainer->_ownsHeap) {
ma_free(pGainer->_pHeap, pAllocationCallbacks);
}
}
static float ma_gainer_calculate_current_gain(const ma_gainer* pGainer, ma_uint32 channel)
{
float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames;
return ma_mix_f32_fast(pGainer->pOldGains[channel], pGainer->pNewGains[channel], a);
}
MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
{
ma_uint64 iFrame;
ma_uint32 iChannel;
float* pFramesOutF32 = (float*)pFramesOut;
const float* pFramesInF32 = (const float*)pFramesIn;
if (pGainer == NULL) {
return MA_INVALID_ARGS;
}
if (pGainer->t >= pGainer->config.smoothTimeInFrames) {
/* Fast path. No gain calculation required. */
ma_copy_and_apply_volume_factor_per_channel_f32(pFramesOutF32, pFramesInF32, frameCount, pGainer->config.channels, pGainer->pNewGains);
/* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */
if (pGainer->t == (ma_uint32)-1) {
pGainer->t = pGainer->config.smoothTimeInFrames;
}
} else {
/* Slow path. Need to interpolate the gain for each channel individually. */
/* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */
if (pFramesOut != NULL && pFramesIn != NULL) {
float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames;
float d = 1.0f / pGainer->config.smoothTimeInFrames;
ma_uint32 channelCount = pGainer->config.channels;
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
for (iChannel = 0; iChannel < channelCount; iChannel += 1) {
pFramesOutF32[iChannel] = pFramesInF32[iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a);
}
pFramesOutF32 += channelCount;
pFramesInF32 += channelCount;
a += d;
if (a > 1) {
a = 1;
}
}
}
pGainer->t = (ma_uint32)ma_min(pGainer->t + frameCount, pGainer->config.smoothTimeInFrames);
#if 0 /* Reference implementation. */
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
/* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */
if (pFramesOut != NULL && pFramesIn != NULL) {
for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * ma_gainer_calculate_current_gain(pGainer, iChannel);
}
}
/* Move interpolation time forward, but don't go beyond our smoothing time. */
pGainer->t = ma_min(pGainer->t + 1, pGainer->config.smoothTimeInFrames);
}
#endif
}
return MA_SUCCESS;
}
static void ma_gainer_set_gain_by_index(ma_gainer* pGainer, float newGain, ma_uint32 iChannel)
{
pGainer->pOldGains[iChannel] = ma_gainer_calculate_current_gain(pGainer, iChannel);
pGainer->pNewGains[iChannel] = newGain;
}
static void ma_gainer_reset_smoothing_time(ma_gainer* pGainer)
{
if (pGainer->t == (ma_uint32)-1) {
pGainer->t = pGainer->config.smoothTimeInFrames; /* No smoothing required for initial gains setting. */
} else {
pGainer->t = 0;
}
}
MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain)
{
ma_uint32 iChannel;
if (pGainer == NULL) {
return MA_INVALID_ARGS;
}
for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
ma_gainer_set_gain_by_index(pGainer, newGain, iChannel);
}
/* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */
ma_gainer_reset_smoothing_time(pGainer);
return MA_SUCCESS;
}
MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains)
{
ma_uint32 iChannel;
if (pGainer == NULL || pNewGains == NULL) {
return MA_INVALID_ARGS;
}
for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
ma_gainer_set_gain_by_index(pGainer, pNewGains[iChannel], iChannel);
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
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;
}
}
}
/**************************************************************************************************************************************************************
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;
}
typedef struct
{
size_t sizeInBytes;
size_t x0Offset;
size_t x1Offset;
size_t lpfOffset;
} ma_linear_resampler_heap_layout;
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, void* pHeap, ma_linear_resampler_heap_layout* pHeapLayout, 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_preallocated(&lpfConfig, ma_offset_ptr(pHeap, pHeapLayout->lpfOffset), &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;
}
static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_config* pConfig, ma_linear_resampler_heap_layout* pHeapLayout)
{
MA_ASSERT(pHeapLayout != NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
return MA_INVALID_ARGS;
}
if (pConfig->channels == 0) {
return MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes = 0;
/* x0 */
pHeapLayout->x0Offset = pHeapLayout->sizeInBytes;
if (pConfig->format == ma_format_f32) {
pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels;
} else {
pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels;
}
/* x1 */
pHeapLayout->x1Offset = pHeapLayout->sizeInBytes;
if (pConfig->format == ma_format_f32) {
pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels;
} else {
pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels;
}
/* LPF */
pHeapLayout->lpfOffset = pHeapLayout->sizeInBytes;
{
ma_result result;
size_t lpfHeapSizeInBytes;
ma_lpf_config lpfConfig = ma_lpf_config_init(pConfig->format, pConfig->channels, 1, 1, pConfig->lpfOrder); /* Sample rate and cutoff frequency do not matter. */
result = ma_lpf_get_heap_size(&lpfConfig, &lpfHeapSizeInBytes);
if (result != MA_SUCCESS) {
return result;
}
pHeapLayout->sizeInBytes += lpfHeapSizeInBytes;
}
/* Make sure allocation size is aligned. */
pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
return MA_SUCCESS;
}