/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.22 - 2025-02-24

David Reid - mackron@gmail.com

Website:       https://miniaud.io
Documentation: https://miniaud.io/docs
GitHub:        https://github.com/mackron/miniaudio

*** This is a stripped down version of miniaudio with only audio IO - decoding, encoding and audio generation has been removed ***
*/
#ifndef miniaudio_h
#define miniaudio_h
#define Mr return
#define Md pDevice
#define Mc pContext
#define Me ma_result
#define Mf result
#define M6 ma_uint64
#define M3 ma_uint32
#define Ms MA_SUCCESS
#define Mv void
#define Mo pConfig
#define Mh channels
#define Mp pDescriptorPlayback
#define Mt ma_device_type_playback
#ifdef __cplusplus
extern "C" {
#endif
#define MA_STRINGIFY(x) #x
#define MA_XSTRINGIFY(x) MA_STRINGIFY(x)
#define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 11
#define MA_VERSION_REVISION 22
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER)&&!defined(__clang__)
#pragma warning(push)
#pragma warning(disable:4201)
#pragma warning(disable:4214)
#pragma warning(disable:4324)
#elif defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=8)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc11-extensions"
#endif
#endif
#if defined(__LP64__)||defined(_WIN64)||(defined(__x86_64__)&&!defined(__ILP32__))||defined(_M_X64)||defined(__ia64)||defined(_M_IA64)||defined(__aarch64__)||defined(_M_ARM64)||defined(__powerpc64__)||defined(__ppc64__)
#define MA_SIZEOF_PTR 8
#else
#define MA_SIZEOF_PTR 4
#endif
#include <stddef.h>
#if defined(MA_USE_STDINT)
#include <stdint.h>
typedef int8_t ma_int8;
typedef uint8_t ma_uint8;
typedef int16_t ma_int16;
typedef uint16_t ma_uint16;
typedef int32_t ma_int32;
typedef uint32_t M3;
typedef int64_t ma_int64;
typedef uint64_t M6;
#else
typedef signed char ma_int8;
typedef unsigned char ma_uint8;
typedef signed short ma_int16;
typedef unsigned short ma_uint16;
typedef signed int ma_int32;
typedef unsigned int M3;
#if defined(_MSC_VER)&&!defined(__clang__)
typedef signed __int64 ma_int64;
typedef unsigned __int64 M6;
#else
#if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc++11-long-long"
#endif
#endif
typedef signed long long ma_int64;
typedef unsigned long long M6;
#if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=6)))
#pragma GCC diagnostic pop
#endif
#endif
#endif
#if MA_SIZEOF_PTR==8
typedef M6 ma_uintptr;
#else
typedef M3 ma_uintptr;
#endif
typedef ma_uint8 ma_bool8;
typedef M3 ma_bool32;
#define MA_TRUE 1
#define MA_FALSE 0
typedef float ma_float;
typedef double ma_double;
typedef Mv*ma_handle;
typedef Mv*ma_ptr;
#if defined(__GNUC__)
typedef Mv (*ma_proc)(Mv);
#else
typedef Mv*ma_proc;
#endif
#if defined(_MSC_VER)&&!defined(_WCHAR_T_DEFINED)
typedef ma_uint16 wchar_t;
#endif
#ifndef NULL
#define NULL 0
#endif
#if defined(SIZE_MAX)
#define MA_SIZE_MAX SIZE_MAX
#else
#define MA_SIZE_MAX 0xFFFFFFFF
#endif
#if defined(_WIN32)||defined(__COSMOPOLITAN__)
#define MA_WIN32
#if defined(MA_FORCE_UWP)||(defined(WINAPI_FAMILY)&&((defined(WINAPI_FAMILY_PC_APP)&&WINAPI_FAMILY==WINAPI_FAMILY_PC_APP)||(defined(WINAPI_FAMILY_PHONE_APP)&&WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)))
#define MA_WIN32_UWP
#elif defined(WINAPI_FAMILY)&&(defined(WINAPI_FAMILY_GAMES)&&WINAPI_FAMILY==WINAPI_FAMILY_GAMES)
#define MA_WIN32_GDK
#else
#define MA_WIN32_DESKTOP
#endif
#endif
#if !defined(_WIN32)
#define MA_POSIX
#ifndef MA_NO_PTHREAD_IN_HEADER
#include <pthread.h>
typedef pthread_t ma_pthread_t;
typedef pthread_mutex_t ma_pthread_mutex_t;
typedef pthread_cond_t ma_pthread_cond_t;
#else
typedef ma_uintptr ma_pthread_t;
typedef union ma_pthread_mutex_t { char __data[40]; M6 __alignment; } ma_pthread_mutex_t;
typedef union ma_pthread_cond_t { char __data[48]; M6 __alignment; } ma_pthread_cond_t;
#endif
#if defined(__unix__)
#define MA_UNIX
#endif
#if defined(__linux__)
#define MA_LINUX
#endif
#if defined(__APPLE__)
#define MA_APPLE
#endif
#if defined(__DragonFly__)||defined(__FreeBSD__)||defined(__NetBSD__)||defined(__OpenBSD__)
#define MA_BSD
#endif
#if defined(__ANDROID__)
#define MA_ANDROID
#endif
#if defined(__EMSCRIPTEN__)
#define MA_EMSCRIPTEN
#endif
#if defined(__ORBIS__)
#define MA_ORBIS
#endif
#if defined(__PROSPERO__)
#define MA_PROSPERO
#endif
#if defined(__NX__)
#define MA_NX
#endif
#if defined(__BEOS__)||defined(__HAIKU__)
#define MA_BEOS
#endif
#if defined(__HAIKU__)
#define MA_HAIKU
#endif
#endif
#if defined(__has_c_attribute)
#if __has_c_attribute(fallthrough)
#define MA_FALLTHROUGH [[fallthrough]]
#endif
#endif
#if !defined(MA_FALLTHROUGH)&&defined(__has_attribute)&&(defined(__clang__)||defined(__GNUC__))
#if __has_attribute(fallthrough)
#define MA_FALLTHROUGH __attribute__((fallthrough))
#endif
#endif
#if !defined(MA_FALLTHROUGH)
#define MA_FALLTHROUGH ((Mv)0)
#endif
#ifdef _MSC_VER
#define MA_INLINE __forceinline
#if _MSC_VER>=1400
#define MA_NO_INLINE __declspec(noinline)
#else
#define MA_NO_INLINE
#endif
#elif defined(__GNUC__)
#if defined(__STRICT_ANSI__)
#define MA_GNUC_INLINE_HINT __inline__
#else
#define MA_GNUC_INLINE_HINT inline
#endif
#if (__GNUC__>3||(__GNUC__==3&&__GNUC_MINOR__>=2))||defined(__clang__)
#define MA_INLINE MA_GNUC_INLINE_HINT __attribute__((always_inline))
#define MA_NO_INLINE __attribute__((noinline))
#else
#define MA_INLINE MA_GNUC_INLINE_HINT
#define MA_NO_INLINE __attribute__((noinline))
#endif
#elif defined(__WATCOMC__)
#define MA_INLINE __inline
#define MA_NO_INLINE
#else
#define MA_INLINE
#define MA_NO_INLINE
#endif
#if defined(MA_DLL)
#if defined(_WIN32)
#define MA_DLL_IMPORT __declspec(dllimport)
#define MA_DLL_EXPORT __declspec(dllexport)
#define MA_DLL_PRIVATE static
#else
#if defined(__GNUC__)&&__GNUC__>=4
#define MA_DLL_IMPORT __attribute__((visibility("default")))
#define MA_DLL_EXPORT __attribute__((visibility("default")))
#define MA_DLL_PRIVATE __attribute__((visibility("hidden")))
#else
#define MA_DLL_IMPORT
#define MA_DLL_EXPORT
#define MA_DLL_PRIVATE static
#endif
#endif
#endif
#if !defined(MA_API)
#if defined(MA_DLL)
#if defined(MINIAUDIO_IMPLEMENTATION)||defined(MA_IMPLEMENTATION)
#define MA_API MA_DLL_EXPORT
#else
#define MA_API MA_DLL_IMPORT
#endif
#else
#define MA_API extern
#endif
#endif
#if !defined(MA_STATIC)
#if defined(MA_DLL)
#define MA_PRIVATE MA_DLL_PRIVATE
#else
#define MA_PRIVATE static
#endif
#endif
#define MA_SIMD_ALIGNMENT 32
#if !defined(MA_POSIX)&&defined(MA_WIN32)
typedef wchar_t ma_wchar_win32;
#else
typedef ma_uint16 ma_wchar_win32;
#endif
typedef enum
{
MA_LOG_LEVEL_DEBUG=4,MA_LOG_LEVEL_INFO=3,MA_LOG_LEVEL_WARNING=2,MA_LOG_LEVEL_ERROR=1
} ma_log_level;
#if !defined(_MSC_VER)&&defined (__STDC_VERSION__)&&(__STDC_VERSION__>=201112L)
#include <stdalign.h>
#define MA_ATOMIC(alignment,type) _Alignas(alignment) type
#else
#if defined(__GNUC__)
#define MA_ATOMIC(alignment,type) type __attribute__((aligned(alignment)))
#elif defined(_MSC_VER)&&_MSC_VER>1200
#define MA_ATOMIC(alignment,type) __declspec(align(alignment)) type
#else
#define MA_ATOMIC(alignment,type) type
#endif
#endif
typedef struct ma_context ma_context;
typedef struct ma_device ma_device;
typedef ma_uint8 ma_channel;
typedef enum
{
MA_CHANNEL_NONE=0,MA_CHANNEL_MONO=1,MA_CHANNEL_FRONT_LEFT=2,MA_CHANNEL_FRONT_RIGHT=3,MA_CHANNEL_FRONT_CENTER=4,MA_CHANNEL_LFE=5,MA_CHANNEL_BACK_LEFT=6,MA_CHANNEL_BACK_RIGHT=7,MA_CHANNEL_FRONT_LEFT_CENTER=8,MA_CHANNEL_FRONT_RIGHT_CENTER=9,MA_CHANNEL_BACK_CENTER=10,MA_CHANNEL_SIDE_LEFT=11,MA_CHANNEL_SIDE_RIGHT=12,MA_CHANNEL_TOP_CENTER=13,MA_CHANNEL_TOP_FRONT_LEFT=14,MA_CHANNEL_TOP_FRONT_CENTER=15,MA_CHANNEL_TOP_FRONT_RIGHT=16,MA_CHANNEL_TOP_BACK_LEFT=17,MA_CHANNEL_TOP_BACK_CENTER=18,MA_CHANNEL_TOP_BACK_RIGHT=19,MA_CHANNEL_AUX_0=20,MA_CHANNEL_AUX_1=21,MA_CHANNEL_AUX_2=22,MA_CHANNEL_AUX_3=23,MA_CHANNEL_AUX_4=24,MA_CHANNEL_AUX_5=25,MA_CHANNEL_AUX_6=26,MA_CHANNEL_AUX_7=27,MA_CHANNEL_AUX_8=28,MA_CHANNEL_AUX_9=29,MA_CHANNEL_AUX_10=30,MA_CHANNEL_AUX_11=31,MA_CHANNEL_AUX_12=32,MA_CHANNEL_AUX_13=33,MA_CHANNEL_AUX_14=34,MA_CHANNEL_AUX_15=35,MA_CHANNEL_AUX_16=36,MA_CHANNEL_AUX_17=37,MA_CHANNEL_AUX_18=38,MA_CHANNEL_AUX_19=39,MA_CHANNEL_AUX_20=40,MA_CHANNEL_AUX_21=41,MA_CHANNEL_AUX_22=42,MA_CHANNEL_AUX_23=43,MA_CHANNEL_AUX_24=44,MA_CHANNEL_AUX_25=45,MA_CHANNEL_AUX_26=46,MA_CHANNEL_AUX_27=47,MA_CHANNEL_AUX_28=48,MA_CHANNEL_AUX_29=49,MA_CHANNEL_AUX_30=50,MA_CHANNEL_AUX_31=51,MA_CHANNEL_LEFT=MA_CHANNEL_FRONT_LEFT,MA_CHANNEL_RIGHT=MA_CHANNEL_FRONT_RIGHT,MA_CHANNEL_POSITION_COUNT=(MA_CHANNEL_AUX_31+1)
} _ma_channel_position;
typedef enum
{
Ms=0,MA_ERROR=-1,MA_INVALID_ARGS=-2,MA_INVALID_OPERATION=-3,MA_OUT_OF_MEMORY=-4,MA_OUT_OF_RANGE=-5,MA_ACCESS_DENIED=-6,MA_DOES_NOT_EXIST=-7,MA_ALREADY_EXISTS=-8,MA_TOO_MANY_OPEN_FILES=-9,MA_INVALID_FILE=-10,MA_TOO_BIG=-11,MA_PATH_TOO_LONG=-12,MA_NAME_TOO_LONG=-13,MA_NOT_DIRECTORY=-14,MA_IS_DIRECTORY=-15,MA_DIRECTORY_NOT_EMPTY=-16,MA_AT_END=-17,MA_NO_SPACE=-18,MA_BUSY=-19,MA_IO_ERROR=-20,MA_INTERRUPT=-21,MA_UNAVAILABLE=-22,MA_ALREADY_IN_USE=-23,MA_BAD_ADDRESS=-24,MA_BAD_SEEK=-25,MA_BAD_PIPE=-26,MA_DEADLOCK=-27,MA_TOO_MANY_LINKS=-28,MA_NOT_IMPLEMENTED=-29,MA_NO_MESSAGE=-30,MA_BAD_MESSAGE=-31,MA_NO_DATA_AVAILABLE=-32,MA_INVALID_DATA=-33,MA_TIMEOUT=-34,MA_NO_NETWORK=-35,MA_NOT_UNIQUE=-36,MA_NOT_SOCKET=-37,MA_NO_ADDRESS=-38,MA_BAD_PROTOCOL=-39,MA_PROTOCOL_UNAVAILABLE=-40,MA_PROTOCOL_NOT_SUPPORTED=-41,MA_PROTOCOL_FAMILY_NOT_SUPPORTED=-42,MA_ADDRESS_FAMILY_NOT_SUPPORTED=-43,MA_SOCKET_NOT_SUPPORTED=-44,MA_CONNECTION_RESET=-45,MA_ALREADY_CONNECTED=-46,MA_NOT_CONNECTED=-47,MA_CONNECTION_REFUSED=-48,MA_NO_HOST=-49,MA_IN_PROGRESS=-50,MA_CANCELLED=-51,MA_MEMORY_ALREADY_MAPPED=-52,MA_CRC_MISMATCH=-100,MA_FORMAT_NOT_SUPPORTED=-200,MA_DEVICE_TYPE_NOT_SUPPORTED=-201,MA_SHARE_MODE_NOT_SUPPORTED=-202,MA_NO_BACKEND=-203,MA_NO_DEVICE=-204,MA_API_NOT_FOUND=-205,MA_INVALID_DEVICE_CONFIG=-206,MA_LOOP=-207,MA_BACKEND_NOT_ENABLED=-208,MA_DEVICE_NOT_INITIALIZED=-300,MA_DEVICE_ALREADY_INITIALIZED=-301,MA_DEVICE_NOT_STARTED=-302,MA_DEVICE_NOT_STOPPED=-303,MA_FAILED_TO_INIT_BACKEND=-400,MA_FAILED_TO_OPEN_BACKEND_DEVICE=-401,MA_FAILED_TO_START_BACKEND_DEVICE=-402,MA_FAILED_TO_STOP_BACKEND_DEVICE=-403
} Me;
#define MA_MIN_CHANNELS 1
#ifndef MA_MAX_CHANNELS
#define MA_MAX_CHANNELS 254
#endif
#ifndef MA_MAX_FILTER_ORDER
#define MA_MAX_FILTER_ORDER 8
#endif
typedef enum
{
ma_stream_format_pcm=0
} ma_stream_format;
typedef enum
{
ma_stream_layout_interleaved=0,ma_stream_layout_deinterleaved
} ma_stream_layout;
typedef enum
{
ma_dither_mode_none=0,ma_dither_mode_rectangle,ma_dither_mode_triangle
} ma_dither_mode;
typedef enum
{
ma_format_unknown=0,ma_format_u8=1,ma_format_s16=2,ma_format_s24=3,ma_format_s32=4,ma_format_f32=5,ma_format_count
} ma_format;
typedef enum
{
ma_standard_sample_rate_48000=48000,ma_standard_sample_rate_44100=44100,ma_standard_sample_rate_32000=32000,ma_standard_sample_rate_24000=24000,ma_standard_sample_rate_22050=22050,ma_standard_sample_rate_88200=88200,ma_standard_sample_rate_96000=96000,ma_standard_sample_rate_176400=176400,ma_standard_sample_rate_192000=192000,ma_standard_sample_rate_16000=16000,ma_standard_sample_rate_11025=11025,ma_standard_sample_rate_8000=8000,ma_standard_sample_rate_352800=352800,ma_standard_sample_rate_384000=384000,ma_standard_sample_rate_min=ma_standard_sample_rate_8000,ma_standard_sample_rate_max=ma_standard_sample_rate_384000,ma_standard_sample_rate_count=14
} ma_standard_sample_rate;
typedef enum
{
ma_channel_mix_mode_rectangular=0,ma_channel_mix_mode_simple,ma_channel_mix_mode_custom_weights,ma_channel_mix_mode_default=ma_channel_mix_mode_rectangular
} ma_channel_mix_mode;
typedef enum
{
ma_standard_channel_map_microsoft,ma_standard_channel_map_alsa,ma_standard_channel_map_rfc3551,ma_standard_channel_map_flac,ma_standard_channel_map_vorbis,ma_standard_channel_map_sound4,ma_standard_channel_map_sndio,ma_standard_channel_map_webaudio=ma_standard_channel_map_flac,ma_standard_channel_map_default=ma_standard_channel_map_microsoft
} ma_standard_channel_map;
typedef enum
{
ma_performance_profile_low_latency=0,ma_performance_profile_conservative
} ma_performance_profile;
typedef struct
{
Mv*pUserData;
Mv*(*onMalloc)(size_t sz,Mv*pUserData);
Mv*(*onRealloc)(Mv*p,size_t sz,Mv*pUserData);
Mv (*onFree)(Mv*p,Mv*pUserData);
} ma_allocation_callbacks;
typedef struct
{
ma_int32 state;
} ma_lcg;
#define MA_ATOMIC_SAFE_TYPE_DECL(c89TypeExtension,typeSize,type)\
typedef struct\
{\
MA_ATOMIC(typeSize,ma_##type) value;\
} ma_atomic_##type;
#define MA_ATOMIC_SAFE_TYPE_DECL_PTR(type)\
typedef struct\
{\
MA_ATOMIC(MA_SIZEOF_PTR,ma_##type*) value;\
} ma_atomic_ptr_##type;
MA_ATOMIC_SAFE_TYPE_DECL(32,4,uint32)
MA_ATOMIC_SAFE_TYPE_DECL(i32,4,int32)
MA_ATOMIC_SAFE_TYPE_DECL(64,8,uint64)
MA_ATOMIC_SAFE_TYPE_DECL(f32,4,float)
MA_ATOMIC_SAFE_TYPE_DECL(32,4,bool32)
typedef M3 ma_spinlock;
#ifndef MA_NO_THREADING
typedef enum
{
ma_thread_priority_idle=-5,ma_thread_priority_lowest=-4,ma_thread_priority_low=-3,ma_thread_priority_normal=-2,ma_thread_priority_high=-1,ma_thread_priority_highest=0,ma_thread_priority_realtime=1,ma_thread_priority_default=0
} ma_thread_priority;
#if defined(MA_POSIX)
typedef ma_pthread_t ma_thread;
#elif defined(MA_WIN32)
typedef ma_handle ma_thread;
#endif
#if defined(MA_POSIX)
typedef ma_pthread_mutex_t ma_mutex;
#elif defined(MA_WIN32)
typedef ma_handle ma_mutex;
#endif
#if defined(MA_POSIX)
typedef struct
{
M3 value;
ma_pthread_mutex_t lock;
ma_pthread_cond_t cond;
} ma_event;
#elif defined(MA_WIN32)
typedef ma_handle ma_event;
#endif
#if defined(MA_POSIX)
typedef struct
{
int value;
ma_pthread_mutex_t lock;
ma_pthread_cond_t cond;
} ma_semaphore;
#elif defined(MA_WIN32)
typedef ma_handle ma_semaphore;
#endif
#else
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif
MA_API Mv ma_version(M3*pMajor,M3*pMinor,M3*pRevision);
MA_API const char*ma_version_string(Mv);
#include <stdarg.h>
#if defined(__has_attribute)
#if __has_attribute(format)
#define MA_ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va)))
#endif
#endif
#ifndef MA_ATTRIBUTE_FORMAT
#define MA_ATTRIBUTE_FORMAT(fmt,va)
#endif
#ifndef MA_MAX_LOG_CALLBACKS
#define MA_MAX_LOG_CALLBACKS 4
#endif
typedef Mv (*ma_log_callback_proc)(Mv*pUserData,M3 level,const char*pMessage);
typedef struct
{
ma_log_callback_proc onLog;
Mv*pUserData;
} ma_log_callback;
MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog,Mv*pUserData);
typedef struct
{
ma_log_callback callbacks[MA_MAX_LOG_CALLBACKS];
M3 callbackCount;
ma_allocation_callbacks allocationCallbacks;
#ifndef MA_NO_THREADING
ma_mutex lock;
#endif
} ma_log;
MA_API Me ma_log_init(const ma_allocation_callbacks*pAllocationCallbacks,ma_log*pLog);
MA_API Mv ma_log_uninit(ma_log*pLog);
MA_API Me ma_log_register_callback(ma_log*pLog,ma_log_callback callback);
MA_API Me ma_log_unregister_callback(ma_log*pLog,ma_log_callback callback);
MA_API Me ma_log_post(ma_log*pLog,M3 level,const char*pMessage);
MA_API Me ma_log_postv(ma_log*pLog,M3 level,const char*pFormat,va_list args);
MA_API Me ma_log_postf(ma_log*pLog,M3 level,const char*pFormat,...) MA_ATTRIBUTE_FORMAT(3,4);
typedef union
{
float f32;
ma_int32 s32;
} ma_biquad_coefficient;
typedef struct
{
ma_format format;
M3 Mh;
double b0;
double b1;
double b2;
double a0;
double a1;
double a2;
} ma_biquad_config;
MA_API ma_biquad_config ma_biquad_config_init(ma_format format,M3 Mh,double b0,double b1,double b2,double a0,double a1,double a2);
typedef struct
{
ma_format format;
M3 Mh;
ma_biquad_coefficient b0;
ma_biquad_coefficient b1;
ma_biquad_coefficient b2;
ma_biquad_coefficient a1;
ma_biquad_coefficient a2;
ma_biquad_coefficient*pR1;
ma_biquad_coefficient*pR2;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_biquad;
MA_API Me ma_biquad_get_heap_size(const ma_biquad_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_biquad_init_preallocated(const ma_biquad_config*Mo,Mv*pHeap,ma_biquad*pBQ);
MA_API Me ma_biquad_init(const ma_biquad_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_biquad*pBQ);
MA_API Mv ma_biquad_uninit(ma_biquad*pBQ,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_biquad_reinit(const ma_biquad_config*Mo,ma_biquad*pBQ);
MA_API Me ma_biquad_clear_cache(ma_biquad*pBQ);
MA_API Me ma_biquad_process_pcm_frames(ma_biquad*pBQ,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_biquad_get_latency(const ma_biquad*pBQ);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double cutoffFrequency;
double q;
} ma_lpf1_config,ma_lpf2_config;
MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency);
MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,double q);
typedef struct
{
ma_format format;
M3 Mh;
ma_biquad_coefficient a;
ma_biquad_coefficient*pR1;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_lpf1;
MA_API Me ma_lpf1_get_heap_size(const ma_lpf1_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_lpf1_init_preallocated(const ma_lpf1_config*Mo,Mv*pHeap,ma_lpf1*pLPF);
MA_API Me ma_lpf1_init(const ma_lpf1_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_lpf1*pLPF);
MA_API Mv ma_lpf1_uninit(ma_lpf1*pLPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_lpf1_reinit(const ma_lpf1_config*Mo,ma_lpf1*pLPF);
MA_API Me ma_lpf1_clear_cache(ma_lpf1*pLPF);
MA_API Me ma_lpf1_process_pcm_frames(ma_lpf1*pLPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_lpf1_get_latency(const ma_lpf1*pLPF);
typedef struct
{
ma_biquad bq;
} ma_lpf2;
MA_API Me ma_lpf2_get_heap_size(const ma_lpf2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_lpf2_init_preallocated(const ma_lpf2_config*Mo,Mv*pHeap,ma_lpf2*pHPF);
MA_API Me ma_lpf2_init(const ma_lpf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_lpf2*pLPF);
MA_API Mv ma_lpf2_uninit(ma_lpf2*pLPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_lpf2_reinit(const ma_lpf2_config*Mo,ma_lpf2*pLPF);
MA_API Me ma_lpf2_clear_cache(ma_lpf2*pLPF);
MA_API Me ma_lpf2_process_pcm_frames(ma_lpf2*pLPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_lpf2_get_latency(const ma_lpf2*pLPF);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double cutoffFrequency;
M3 order;
} ma_lpf_config;
MA_API ma_lpf_config ma_lpf_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,M3 order);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
M3 lpf1Count;
M3 lpf2Count;
ma_lpf1*pLPF1;
ma_lpf2*pLPF2;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_lpf;
MA_API Me ma_lpf_get_heap_size(const ma_lpf_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_lpf_init_preallocated(const ma_lpf_config*Mo,Mv*pHeap,ma_lpf*pLPF);
MA_API Me ma_lpf_init(const ma_lpf_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_lpf*pLPF);
MA_API Mv ma_lpf_uninit(ma_lpf*pLPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_lpf_reinit(const ma_lpf_config*Mo,ma_lpf*pLPF);
MA_API Me ma_lpf_clear_cache(ma_lpf*pLPF);
MA_API Me ma_lpf_process_pcm_frames(ma_lpf*pLPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_lpf_get_latency(const ma_lpf*pLPF);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double cutoffFrequency;
double q;
} ma_hpf1_config,ma_hpf2_config;
MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency);
MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,double q);
typedef struct
{
ma_format format;
M3 Mh;
ma_biquad_coefficient a;
ma_biquad_coefficient*pR1;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_hpf1;
MA_API Me ma_hpf1_get_heap_size(const ma_hpf1_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_hpf1_init_preallocated(const ma_hpf1_config*Mo,Mv*pHeap,ma_hpf1*pLPF);
MA_API Me ma_hpf1_init(const ma_hpf1_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hpf1*pHPF);
MA_API Mv ma_hpf1_uninit(ma_hpf1*pHPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_hpf1_reinit(const ma_hpf1_config*Mo,ma_hpf1*pHPF);
MA_API Me ma_hpf1_process_pcm_frames(ma_hpf1*pHPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_hpf1_get_latency(const ma_hpf1*pHPF);
typedef struct
{
ma_biquad bq;
} ma_hpf2;
MA_API Me ma_hpf2_get_heap_size(const ma_hpf2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_hpf2_init_preallocated(const ma_hpf2_config*Mo,Mv*pHeap,ma_hpf2*pHPF);
MA_API Me ma_hpf2_init(const ma_hpf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hpf2*pHPF);
MA_API Mv ma_hpf2_uninit(ma_hpf2*pHPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_hpf2_reinit(const ma_hpf2_config*Mo,ma_hpf2*pHPF);
MA_API Me ma_hpf2_process_pcm_frames(ma_hpf2*pHPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_hpf2_get_latency(const ma_hpf2*pHPF);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double cutoffFrequency;
M3 order;
} ma_hpf_config;
MA_API ma_hpf_config ma_hpf_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,M3 order);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
M3 hpf1Count;
M3 hpf2Count;
ma_hpf1*pHPF1;
ma_hpf2*pHPF2;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_hpf;
MA_API Me ma_hpf_get_heap_size(const ma_hpf_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_hpf_init_preallocated(const ma_hpf_config*Mo,Mv*pHeap,ma_hpf*pLPF);
MA_API Me ma_hpf_init(const ma_hpf_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hpf*pHPF);
MA_API Mv ma_hpf_uninit(ma_hpf*pHPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_hpf_reinit(const ma_hpf_config*Mo,ma_hpf*pHPF);
MA_API Me ma_hpf_process_pcm_frames(ma_hpf*pHPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_hpf_get_latency(const ma_hpf*pHPF);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double cutoffFrequency;
double q;
} ma_bpf2_config;
MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,double q);
typedef struct
{
ma_biquad bq;
} ma_bpf2;
MA_API Me ma_bpf2_get_heap_size(const ma_bpf2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_bpf2_init_preallocated(const ma_bpf2_config*Mo,Mv*pHeap,ma_bpf2*pBPF);
MA_API Me ma_bpf2_init(const ma_bpf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_bpf2*pBPF);
MA_API Mv ma_bpf2_uninit(ma_bpf2*pBPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_bpf2_reinit(const ma_bpf2_config*Mo,ma_bpf2*pBPF);
MA_API Me ma_bpf2_process_pcm_frames(ma_bpf2*pBPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_bpf2_get_latency(const ma_bpf2*pBPF);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double cutoffFrequency;
M3 order;
} ma_bpf_config;
MA_API ma_bpf_config ma_bpf_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,M3 order);
typedef struct
{
ma_format format;
M3 Mh;
M3 bpf2Count;
ma_bpf2*pBPF2;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_bpf;
MA_API Me ma_bpf_get_heap_size(const ma_bpf_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_bpf_init_preallocated(const ma_bpf_config*Mo,Mv*pHeap,ma_bpf*pBPF);
MA_API Me ma_bpf_init(const ma_bpf_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_bpf*pBPF);
MA_API Mv ma_bpf_uninit(ma_bpf*pBPF,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_bpf_reinit(const ma_bpf_config*Mo,ma_bpf*pBPF);
MA_API Me ma_bpf_process_pcm_frames(ma_bpf*pBPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_bpf_get_latency(const ma_bpf*pBPF);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double q;
double frequency;
} ma_notch2_config,ma_notch_config;
MA_API ma_notch2_config ma_notch2_config_init(ma_format format,M3 Mh,M3 sampleRate,double q,double frequency);
typedef struct
{
ma_biquad bq;
} ma_notch2;
MA_API Me ma_notch2_get_heap_size(const ma_notch2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_notch2_init_preallocated(const ma_notch2_config*Mo,Mv*pHeap,ma_notch2*pFilter);
MA_API Me ma_notch2_init(const ma_notch2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_notch2*pFilter);
MA_API Mv ma_notch2_uninit(ma_notch2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_notch2_reinit(const ma_notch2_config*Mo,ma_notch2*pFilter);
MA_API Me ma_notch2_process_pcm_frames(ma_notch2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_notch2_get_latency(const ma_notch2*pFilter);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double gainDB;
double q;
double frequency;
} ma_peak2_config,ma_peak_config;
MA_API ma_peak2_config ma_peak2_config_init(ma_format format,M3 Mh,M3 sampleRate,double gainDB,double q,double frequency);
typedef struct
{
ma_biquad bq;
} ma_peak2;
MA_API Me ma_peak2_get_heap_size(const ma_peak2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_peak2_init_preallocated(const ma_peak2_config*Mo,Mv*pHeap,ma_peak2*pFilter);
MA_API Me ma_peak2_init(const ma_peak2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_peak2*pFilter);
MA_API Mv ma_peak2_uninit(ma_peak2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_peak2_reinit(const ma_peak2_config*Mo,ma_peak2*pFilter);
MA_API Me ma_peak2_process_pcm_frames(ma_peak2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_peak2_get_latency(const ma_peak2*pFilter);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double gainDB;
double shelfSlope;
double frequency;
} ma_loshelf2_config,ma_loshelf_config;
MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double gainDB,double shelfSlope,double frequency);
typedef struct
{
ma_biquad bq;
} ma_loshelf2;
MA_API Me ma_loshelf2_get_heap_size(const ma_loshelf2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_loshelf2_init_preallocated(const ma_loshelf2_config*Mo,Mv*pHeap,ma_loshelf2*pFilter);
MA_API Me ma_loshelf2_init(const ma_loshelf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_loshelf2*pFilter);
MA_API Mv ma_loshelf2_uninit(ma_loshelf2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_loshelf2_reinit(const ma_loshelf2_config*Mo,ma_loshelf2*pFilter);
MA_API Me ma_loshelf2_process_pcm_frames(ma_loshelf2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_loshelf2_get_latency(const ma_loshelf2*pFilter);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
double gainDB;
double shelfSlope;
double frequency;
} ma_hishelf2_config,ma_hishelf_config;
MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double gainDB,double shelfSlope,double frequency);
typedef struct
{
ma_biquad bq;
} ma_hishelf2;
MA_API Me ma_hishelf2_get_heap_size(const ma_hishelf2_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_hishelf2_init_preallocated(const ma_hishelf2_config*Mo,Mv*pHeap,ma_hishelf2*pFilter);
MA_API Me ma_hishelf2_init(const ma_hishelf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hishelf2*pFilter);
MA_API Mv ma_hishelf2_uninit(ma_hishelf2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_hishelf2_reinit(const ma_hishelf2_config*Mo,ma_hishelf2*pFilter);
MA_API Me ma_hishelf2_process_pcm_frames(ma_hishelf2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API M3 ma_hishelf2_get_latency(const ma_hishelf2*pFilter);
typedef struct
{
M3 Mh;
M3 sampleRate;
M3 delayInFrames;
ma_bool32 delayStart;
float wet;
float dry;
float decay;
} ma_delay_config;
MA_API ma_delay_config ma_delay_config_init(M3 Mh,M3 sampleRate,M3 delayInFrames,float decay);
typedef struct
{
ma_delay_config config;
M3 cursor;
M3 bufferSizeInFrames;
float*pBuffer;
} ma_delay;
MA_API Me ma_delay_init(const ma_delay_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_delay*pDelay);
MA_API Mv ma_delay_uninit(ma_delay*pDelay,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_delay_process_pcm_frames(ma_delay*pDelay,Mv*pFramesOut,const Mv*pFramesIn,M3 frameCount);
MA_API Mv ma_delay_set_wet(ma_delay*pDelay,float value);
MA_API float ma_delay_get_wet(const ma_delay*pDelay);
MA_API Mv ma_delay_set_dry(ma_delay*pDelay,float value);
MA_API float ma_delay_get_dry(const ma_delay*pDelay);
MA_API Mv ma_delay_set_decay(ma_delay*pDelay,float value);
MA_API float ma_delay_get_decay(const ma_delay*pDelay);
typedef struct
{
M3 Mh;
M3 smoothTimeInFrames;
} ma_gainer_config;
MA_API ma_gainer_config ma_gainer_config_init(M3 Mh,M3 smoothTimeInFrames);
typedef struct
{
ma_gainer_config config;
M3 t;
float masterVolume;
float*pOldGains;
float*pNewGains;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_gainer;
MA_API Me ma_gainer_get_heap_size(const ma_gainer_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_gainer_init_preallocated(const ma_gainer_config*Mo,Mv*pHeap,ma_gainer*pGainer);
MA_API Me ma_gainer_init(const ma_gainer_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_gainer*pGainer);
MA_API Mv ma_gainer_uninit(ma_gainer*pGainer,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_gainer_process_pcm_frames(ma_gainer*pGainer,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API Me ma_gainer_set_gain(ma_gainer*pGainer,float newGain);
MA_API Me ma_gainer_set_gains(ma_gainer*pGainer,float*pNewGains);
MA_API Me ma_gainer_set_master_volume(ma_gainer*pGainer,float volume);
MA_API Me ma_gainer_get_master_volume(const ma_gainer*pGainer,float*pVolume);
typedef enum
{
ma_pan_mode_balance=0,ma_pan_mode_pan
} ma_pan_mode;
typedef struct
{
ma_format format;
M3 Mh;
ma_pan_mode mode;
float pan;
} ma_panner_config;
MA_API ma_panner_config ma_panner_config_init(ma_format format,M3 Mh);
typedef struct
{
ma_format format;
M3 Mh;
ma_pan_mode mode;
float pan;
} ma_panner;
MA_API Me ma_panner_init(const ma_panner_config*Mo,ma_panner*pPanner);
MA_API Me ma_panner_process_pcm_frames(ma_panner*pPanner,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API Mv ma_panner_set_mode(ma_panner*pPanner,ma_pan_mode mode);
MA_API ma_pan_mode ma_panner_get_mode(const ma_panner*pPanner);
MA_API Mv ma_panner_set_pan(ma_panner*pPanner,float pan);
MA_API float ma_panner_get_pan(const ma_panner*pPanner);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
} ma_fader_config;
MA_API ma_fader_config ma_fader_config_init(ma_format format,M3 Mh,M3 sampleRate);
typedef struct
{
ma_fader_config config;
float volumeBeg;
float volumeEnd;
M6 lengthInFrames;
ma_int64 cursorInFrames;
} ma_fader;
MA_API Me ma_fader_init(const ma_fader_config*Mo,ma_fader*pFader);
MA_API Me ma_fader_process_pcm_frames(ma_fader*pFader,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API Mv ma_fader_get_data_format(const ma_fader*pFader,ma_format*pFormat,M3*pChannels,M3*pSampleRate);
MA_API Mv ma_fader_set_fade(ma_fader*pFader,float volumeBeg,float volumeEnd,M6 lengthInFrames);
MA_API Mv ma_fader_set_fade_ex(ma_fader*pFader,float volumeBeg,float volumeEnd,M6 lengthInFrames,ma_int64 startOffsetInFrames);
MA_API float ma_fader_get_current_volume(const ma_fader*pFader);
typedef struct
{
float x;
float y;
float z;
} ma_vec3f;
typedef struct
{
ma_vec3f v;
ma_spinlock lock;
} ma_atomic_vec3f;
typedef enum
{
ma_attenuation_model_none,ma_attenuation_model_inverse,ma_attenuation_model_linear,ma_attenuation_model_exponential
} ma_attenuation_model;
typedef enum
{
ma_positioning_absolute,ma_positioning_relative
} ma_positioning;
typedef enum
{
ma_handedness_right,ma_handedness_left
} ma_handedness;
typedef struct
{
M3 channelsOut;
ma_channel*pChannelMapOut;
ma_handedness handedness;
float coneInnerAngleInRadians;
float coneOuterAngleInRadians;
float coneOuterGain;
float speedOfSound;
ma_vec3f worldUp;
} ma_spatializer_listener_config;
MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(M3 channelsOut);
typedef struct
{
ma_spatializer_listener_config config;
ma_atomic_vec3f position;
ma_atomic_vec3f direction;
ma_atomic_vec3f velocity;
ma_bool32 isEnabled;
ma_bool32 _ownsHeap;
Mv*_pHeap;
} ma_spatializer_listener;
MA_API Me ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config*Mo,Mv*pHeap,ma_spatializer_listener*pListener);
MA_API Me ma_spatializer_listener_init(const ma_spatializer_listener_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_uninit(ma_spatializer_listener*pListener,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API ma_channel*ma_spatializer_listener_get_channel_map(ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_set_cone(ma_spatializer_listener*pListener,float innerAngleInRadians,float outerAngleInRadians,float outerGain);
MA_API Mv ma_spatializer_listener_get_cone(const ma_spatializer_listener*pListener,float*pInnerAngleInRadians,float*pOuterAngleInRadians,float*pOuterGain);
MA_API Mv ma_spatializer_listener_set_position(ma_spatializer_listener*pListener,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_set_direction(ma_spatializer_listener*pListener,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_set_velocity(ma_spatializer_listener*pListener,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener*pListener,float speedOfSound);
MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_set_world_up(ma_spatializer_listener*pListener,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener*pListener);
MA_API Mv ma_spatializer_listener_set_enabled(ma_spatializer_listener*pListener,ma_bool32 isEnabled);
MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener*pListener);
typedef struct
{
M3 channelsIn;
M3 channelsOut;
ma_channel*pChannelMapIn;
ma_attenuation_model attenuationModel;
ma_positioning positioning;
ma_handedness handedness;
float minGain;
float maxGain;
float minDistance;
float maxDistance;
float rolloff;
float coneInnerAngleInRadians;
float coneOuterAngleInRadians;
float coneOuterGain;
float dopplerFactor;
float directionalAttenuationFactor;
float minSpatializationChannelGain;
M3 gainSmoothTimeInFrames;
} ma_spatializer_config;
MA_API ma_spatializer_config ma_spatializer_config_init(M3 channelsIn,M3 channelsOut);
typedef struct
{
M3 channelsIn;
M3 channelsOut;
ma_channel*pChannelMapIn;
ma_attenuation_model attenuationModel;
ma_positioning positioning;
ma_handedness handedness;
float minGain;
float maxGain;
float minDistance;
float maxDistance;
float rolloff;
float coneInnerAngleInRadians;
float coneOuterAngleInRadians;
float coneOuterGain;
float dopplerFactor;
float directionalAttenuationFactor;
M3 gainSmoothTimeInFrames;
ma_atomic_vec3f position;
ma_atomic_vec3f direction;
ma_atomic_vec3f velocity;
float dopplerPitch;
float minSpatializationChannelGain;
ma_gainer gainer;
float*pNewChannelGainsOut;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_spatializer;
MA_API Me ma_spatializer_get_heap_size(const ma_spatializer_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_spatializer_init_preallocated(const ma_spatializer_config*Mo,Mv*pHeap,ma_spatializer*pSpatializer);
MA_API Me ma_spatializer_init(const ma_spatializer_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_uninit(ma_spatializer*pSpatializer,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_spatializer_process_pcm_frames(ma_spatializer*pSpatializer,ma_spatializer_listener*pListener,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API Me ma_spatializer_set_master_volume(ma_spatializer*pSpatializer,float volume);
MA_API Me ma_spatializer_get_master_volume(const ma_spatializer*pSpatializer,float*pVolume);
MA_API M3 ma_spatializer_get_input_channels(const ma_spatializer*pSpatializer);
MA_API M3 ma_spatializer_get_output_channels(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_attenuation_model(ma_spatializer*pSpatializer,ma_attenuation_model attenuationModel);
MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_positioning(ma_spatializer*pSpatializer,ma_positioning positioning);
MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_rolloff(ma_spatializer*pSpatializer,float rolloff);
MA_API float ma_spatializer_get_rolloff(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_min_gain(ma_spatializer*pSpatializer,float minGain);
MA_API float ma_spatializer_get_min_gain(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_max_gain(ma_spatializer*pSpatializer,float maxGain);
MA_API float ma_spatializer_get_max_gain(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_min_distance(ma_spatializer*pSpatializer,float minDistance);
MA_API float ma_spatializer_get_min_distance(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_max_distance(ma_spatializer*pSpatializer,float maxDistance);
MA_API float ma_spatializer_get_max_distance(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_cone(ma_spatializer*pSpatializer,float innerAngleInRadians,float outerAngleInRadians,float outerGain);
MA_API Mv ma_spatializer_get_cone(const ma_spatializer*pSpatializer,float*pInnerAngleInRadians,float*pOuterAngleInRadians,float*pOuterGain);
MA_API Mv ma_spatializer_set_doppler_factor(ma_spatializer*pSpatializer,float dopplerFactor);
MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_directional_attenuation_factor(ma_spatializer*pSpatializer,float directionalAttenuationFactor);
MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_position(ma_spatializer*pSpatializer,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_direction(ma_spatializer*pSpatializer,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_set_velocity(ma_spatializer*pSpatializer,float x,float y,float z);
MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer*pSpatializer);
MA_API Mv ma_spatializer_get_relative_position_and_direction(const ma_spatializer*pSpatializer,const ma_spatializer_listener*pListener,ma_vec3f*pRelativePos,ma_vec3f*pRelativeDir);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRateIn;
M3 sampleRateOut;
M3 lpfOrder;
double lpfNyquistFactor;
} ma_linear_resampler_config;
MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format,M3 Mh,M3 sampleRateIn,M3 sampleRateOut);
typedef struct
{
ma_linear_resampler_config config;
M3 inAdvanceInt;
M3 inAdvanceFrac;
M3 inTimeInt;
M3 inTimeFrac;
union
{
float*f32;
ma_int16*s16;
} x0;
union
{
float*f32;
ma_int16*s16;
} x1;
ma_lpf lpf;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_linear_resampler;
MA_API Me ma_linear_resampler_get_heap_size(const ma_linear_resampler_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_linear_resampler_init_preallocated(const ma_linear_resampler_config*Mo,Mv*pHeap,ma_linear_resampler*pResampler);
MA_API Me ma_linear_resampler_init(const ma_linear_resampler_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_linear_resampler*pResampler);
MA_API Mv ma_linear_resampler_uninit(ma_linear_resampler*pResampler,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_linear_resampler_process_pcm_frames(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut);
MA_API Me ma_linear_resampler_set_rate(ma_linear_resampler*pResampler,M3 sampleRateIn,M3 sampleRateOut);
MA_API Me ma_linear_resampler_set_rate_ratio(ma_linear_resampler*pResampler,float ratioInOut);
MA_API M6 ma_linear_resampler_get_input_latency(const ma_linear_resampler*pResampler);
MA_API M6 ma_linear_resampler_get_output_latency(const ma_linear_resampler*pResampler);
MA_API Me ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler*pResampler,M6 outputFrameCount,M6*pInputFrameCount);
MA_API Me ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler*pResampler,M6 inputFrameCount,M6*pOutputFrameCount);
MA_API Me ma_linear_resampler_reset(ma_linear_resampler*pResampler);
typedef struct ma_resampler_config ma_resampler_config;
typedef Mv ma_resampling_backend;
typedef struct
{
Me (*onGetHeapSize )(Mv*pUserData,const ma_resampler_config*Mo,size_t*pHeapSizeInBytes);
Me (*onInit )(Mv*pUserData,const ma_resampler_config*Mo,Mv*pHeap,ma_resampling_backend**ppBackend);
Mv (*onUninit )(Mv*pUserData,ma_resampling_backend*pBackend,const ma_allocation_callbacks*pAllocationCallbacks);
Me (*onProcess )(Mv*pUserData,ma_resampling_backend*pBackend,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut);
Me (*onSetRate )(Mv*pUserData,ma_resampling_backend*pBackend,M3 sampleRateIn,M3 sampleRateOut);
M6 (*onGetInputLatency )(Mv*pUserData,const ma_resampling_backend*pBackend);
M6 (*onGetOutputLatency )(Mv*pUserData,const ma_resampling_backend*pBackend);
Me (*onGetRequiredInputFrameCount )(Mv*pUserData,const ma_resampling_backend*pBackend,M6 outputFrameCount,M6*pInputFrameCount);
Me (*onGetExpectedOutputFrameCount)(Mv*pUserData,const ma_resampling_backend*pBackend,M6 inputFrameCount,M6*pOutputFrameCount);
Me (*onReset )(Mv*pUserData,ma_resampling_backend*pBackend);
} ma_resampling_backend_vtable;
typedef enum
{
ma_resample_algorithm_linear=0,ma_resample_algorithm_custom,} ma_resample_algorithm;
struct ma_resampler_config
{
ma_format format;
M3 Mh;
M3 sampleRateIn;
M3 sampleRateOut;
ma_resample_algorithm algorithm;
ma_resampling_backend_vtable*pBackendVTable;
Mv*pBackendUserData;
struct
{
M3 lpfOrder;
} linear;
};
MA_API ma_resampler_config ma_resampler_config_init(ma_format format,M3 Mh,M3 sampleRateIn,M3 sampleRateOut,ma_resample_algorithm algorithm);
typedef struct
{
ma_resampling_backend*pBackend;
ma_resampling_backend_vtable*pBackendVTable;
Mv*pBackendUserData;
ma_format format;
M3 Mh;
M3 sampleRateIn;
M3 sampleRateOut;
union
{
ma_linear_resampler linear;
} state;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_resampler;
MA_API Me ma_resampler_get_heap_size(const ma_resampler_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_resampler_init_preallocated(const ma_resampler_config*Mo,Mv*pHeap,ma_resampler*pResampler);
MA_API Me ma_resampler_init(const ma_resampler_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_resampler*pResampler);
MA_API Mv ma_resampler_uninit(ma_resampler*pResampler,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_resampler_process_pcm_frames(ma_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut);
MA_API Me ma_resampler_set_rate(ma_resampler*pResampler,M3 sampleRateIn,M3 sampleRateOut);
MA_API Me ma_resampler_set_rate_ratio(ma_resampler*pResampler,float ratio);
MA_API M6 ma_resampler_get_input_latency(const ma_resampler*pResampler);
MA_API M6 ma_resampler_get_output_latency(const ma_resampler*pResampler);
MA_API Me ma_resampler_get_required_input_frame_count(const ma_resampler*pResampler,M6 outputFrameCount,M6*pInputFrameCount);
MA_API Me ma_resampler_get_expected_output_frame_count(const ma_resampler*pResampler,M6 inputFrameCount,M6*pOutputFrameCount);
MA_API Me ma_resampler_reset(ma_resampler*pResampler);
typedef enum
{
ma_channel_conversion_path_unknown,ma_channel_conversion_path_passthrough,ma_channel_conversion_path_mono_out,ma_channel_conversion_path_mono_in,ma_channel_conversion_path_shuffle,ma_channel_conversion_path_weights
} ma_channel_conversion_path;
typedef enum
{
ma_mono_expansion_mode_duplicate=0,ma_mono_expansion_mode_average,ma_mono_expansion_mode_stereo_only,ma_mono_expansion_mode_default=ma_mono_expansion_mode_duplicate
} ma_mono_expansion_mode;
typedef struct
{
ma_format format;
M3 channelsIn;
M3 channelsOut;
const ma_channel*pChannelMapIn;
const ma_channel*pChannelMapOut;
ma_channel_mix_mode mixingMode;
ma_bool32 calculateLFEFromSpatialChannels;
float**ppWeights;
} ma_channel_converter_config;
MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format,M3 channelsIn,const ma_channel*pChannelMapIn,M3 channelsOut,const ma_channel*pChannelMapOut,ma_channel_mix_mode mixingMode);
typedef struct
{
ma_format format;
M3 channelsIn;
M3 channelsOut;
ma_channel_mix_mode mixingMode;
ma_channel_conversion_path conversionPath;
ma_channel*pChannelMapIn;
ma_channel*pChannelMapOut;
ma_uint8*pShuffleTable;
union
{
float**f32;
ma_int32**s16;
} weights;
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_channel_converter;
MA_API Me ma_channel_converter_get_heap_size(const ma_channel_converter_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_channel_converter_init_preallocated(const ma_channel_converter_config*Mo,Mv*pHeap,ma_channel_converter*pConverter);
MA_API Me ma_channel_converter_init(const ma_channel_converter_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_channel_converter*pConverter);
MA_API Mv ma_channel_converter_uninit(ma_channel_converter*pConverter,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_channel_converter_process_pcm_frames(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount);
MA_API Me ma_channel_converter_get_input_channel_map(const ma_channel_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap);
MA_API Me ma_channel_converter_get_output_channel_map(const ma_channel_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap);
typedef struct
{
ma_format formatIn;
ma_format formatOut;
M3 channelsIn;
M3 channelsOut;
M3 sampleRateIn;
M3 sampleRateOut;
ma_channel*pChannelMapIn;
ma_channel*pChannelMapOut;
ma_dither_mode ditherMode;
ma_channel_mix_mode channelMixMode;
ma_bool32 calculateLFEFromSpatialChannels;
float**ppChannelWeights;
ma_bool32 allowDynamicSampleRate;
ma_resampler_config resampling;
} ma_data_converter_config;
MA_API ma_data_converter_config ma_data_converter_config_init_default(Mv);
MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn,ma_format formatOut,M3 channelsIn,M3 channelsOut,M3 sampleRateIn,M3 sampleRateOut);
typedef enum
{
ma_data_converter_execution_path_passthrough,ma_data_converter_execution_path_format_only,ma_data_converter_execution_path_channels_only,ma_data_converter_execution_path_resample_only,ma_data_converter_execution_path_resample_first,ma_data_converter_execution_path_channels_first
} ma_data_converter_execution_path;
typedef struct
{
ma_format formatIn;
ma_format formatOut;
M3 channelsIn;
M3 channelsOut;
M3 sampleRateIn;
M3 sampleRateOut;
ma_dither_mode ditherMode;
ma_data_converter_execution_path executionPath;
ma_channel_converter channelConverter;
ma_resampler resampler;
ma_bool8 hasPreFormatConversion;
ma_bool8 hasPostFormatConversion;
ma_bool8 hasChannelConverter;
ma_bool8 hasResampler;
ma_bool8 isPassthrough;
ma_bool8 _ownsHeap;
Mv*_pHeap;
} ma_data_converter;
MA_API Me ma_data_converter_get_heap_size(const ma_data_converter_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_data_converter_init_preallocated(const ma_data_converter_config*Mo,Mv*pHeap,ma_data_converter*pConverter);
MA_API Me ma_data_converter_init(const ma_data_converter_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_data_converter*pConverter);
MA_API Mv ma_data_converter_uninit(ma_data_converter*pConverter,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_data_converter_process_pcm_frames(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut);
MA_API Me ma_data_converter_set_rate(ma_data_converter*pConverter,M3 sampleRateIn,M3 sampleRateOut);
MA_API Me ma_data_converter_set_rate_ratio(ma_data_converter*pConverter,float ratioInOut);
MA_API M6 ma_data_converter_get_input_latency(const ma_data_converter*pConverter);
MA_API M6 ma_data_converter_get_output_latency(const ma_data_converter*pConverter);
MA_API Me ma_data_converter_get_required_input_frame_count(const ma_data_converter*pConverter,M6 outputFrameCount,M6*pInputFrameCount);
MA_API Me ma_data_converter_get_expected_output_frame_count(const ma_data_converter*pConverter,M6 inputFrameCount,M6*pOutputFrameCount);
MA_API Me ma_data_converter_get_input_channel_map(const ma_data_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap);
MA_API Me ma_data_converter_get_output_channel_map(const ma_data_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap);
MA_API Me ma_data_converter_reset(ma_data_converter*pConverter);
MA_API Mv ma_pcm_u8_to_s16(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_u8_to_s24(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_u8_to_s32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_u8_to_f32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s16_to_u8(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s16_to_s24(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s16_to_s32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s16_to_f32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s24_to_u8(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s24_to_s16(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s24_to_s32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s24_to_f32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s32_to_u8(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s32_to_s16(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s32_to_s24(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_s32_to_f32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_f32_to_u8(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_f32_to_s16(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_f32_to_s24(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_f32_to_s32(Mv*pOut,const Mv*pIn,M6 count,ma_dither_mode ditherMode);
MA_API Mv ma_pcm_convert(Mv*pOut,ma_format formatOut,const Mv*pIn,ma_format formatIn,M6 sampleCount,ma_dither_mode ditherMode);
MA_API Mv ma_convert_pcm_frames_format(Mv*pOut,ma_format formatOut,const Mv*pIn,ma_format formatIn,M6 frameCount,M3 Mh,ma_dither_mode ditherMode);
MA_API Mv ma_deinterleave_pcm_frames(ma_format format,M3 Mh,M6 frameCount,const Mv*pInterleavedPCMFrames,Mv**ppDeinterleavedPCMFrames);
MA_API Mv ma_interleave_pcm_frames(ma_format format,M3 Mh,M6 frameCount,const Mv**ppDeinterleavedPCMFrames,Mv*pInterleavedPCMFrames);
#define MA_CHANNEL_INDEX_NULL 255
MA_API ma_channel ma_channel_map_get_channel(const ma_channel*pChannelMap,M3 channelCount,M3 channelIndex);
MA_API Mv ma_channel_map_init_blank(ma_channel*pChannelMap,M3 Mh);
MA_API Mv ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap,ma_channel*pChannelMap,size_t channelMapCap,M3 Mh);
MA_API Mv ma_channel_map_copy(ma_channel*pOut,const ma_channel*pIn,M3 Mh);
MA_API Mv ma_channel_map_copy_or_default(ma_channel*pOut,size_t channelMapCapOut,const ma_channel*pIn,M3 Mh);
MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel*pChannelMap,M3 Mh);
MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel*pChannelMapA,const ma_channel*pChannelMapB,M3 Mh);
MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel*pChannelMap,M3 Mh);
MA_API ma_bool32 ma_channel_map_contains_channel_position(M3 Mh,const ma_channel*pChannelMap,ma_channel channelPosition);
MA_API ma_bool32 ma_channel_map_find_channel_position(M3 Mh,const ma_channel*pChannelMap,ma_channel channelPosition,M3*pChannelIndex);
MA_API size_t ma_channel_map_to_string(const ma_channel*pChannelMap,M3 Mh,char*pBufferOut,size_t bufferCap);
MA_API const char*ma_channel_position_to_string(ma_channel channel);
MA_API M6 ma_convert_frames(Mv*pOut,M6 frameCountOut,ma_format formatOut,M3 channelsOut,M3 sampleRateOut,const Mv*pIn,M6 frameCountIn,ma_format formatIn,M3 channelsIn,M3 sampleRateIn);
MA_API M6 ma_convert_frames_ex(Mv*pOut,M6 frameCountOut,const Mv*pIn,M6 frameCountIn,const ma_data_converter_config*Mo);
typedef Mv ma_data_source;
#define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 0x00000001
typedef struct
{
Me (*onRead)(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead);
Me (*onSeek)(ma_data_source*pDataSource,M6 frameIndex);
Me (*onGetDataFormat)(ma_data_source*pDataSource,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap);
Me (*onGetCursor)(ma_data_source*pDataSource,M6*pCursor);
Me (*onGetLength)(ma_data_source*pDataSource,M6*pLength);
Me (*onSetLooping)(ma_data_source*pDataSource,ma_bool32 isLooping);
M3 flags;
} ma_data_source_vtable;
typedef ma_data_source*(*ma_data_source_get_next_proc)(ma_data_source*pDataSource);
typedef struct
{
const ma_data_source_vtable*vtable;
} ma_data_source_config;
MA_API ma_data_source_config ma_data_source_config_init(Mv);
typedef struct
{
const ma_data_source_vtable*vtable;
M6 rangeBegInFrames;
M6 rangeEndInFrames;
M6 loopBegInFrames;
M6 loopEndInFrames;
ma_data_source*pCurrent;
ma_data_source*pNext;
ma_data_source_get_next_proc onGetNext;
MA_ATOMIC(4,ma_bool32) isLooping;
} ma_data_source_base;
MA_API Me ma_data_source_init(const ma_data_source_config*Mo,ma_data_source*pDataSource);
MA_API Mv ma_data_source_uninit(ma_data_source*pDataSource);
MA_API Me ma_data_source_read_pcm_frames(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead);
MA_API Me ma_data_source_seek_pcm_frames(ma_data_source*pDataSource,M6 frameCount,M6*pFramesSeeked);
MA_API Me ma_data_source_seek_to_pcm_frame(ma_data_source*pDataSource,M6 frameIndex);
MA_API Me ma_data_source_seek_seconds(ma_data_source*pDataSource,float secondCount,float*pSecondsSeeked);
MA_API Me ma_data_source_seek_to_second(ma_data_source*pDataSource,float seekPointInSeconds);
MA_API Me ma_data_source_get_data_format(ma_data_source*pDataSource,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap);
MA_API Me ma_data_source_get_cursor_in_pcm_frames(ma_data_source*pDataSource,M6*pCursor);
MA_API Me ma_data_source_get_length_in_pcm_frames(ma_data_source*pDataSource,M6*pLength);
MA_API Me ma_data_source_get_cursor_in_seconds(ma_data_source*pDataSource,float*pCursor);
MA_API Me ma_data_source_get_length_in_seconds(ma_data_source*pDataSource,float*pLength);
MA_API Me ma_data_source_set_looping(ma_data_source*pDataSource,ma_bool32 isLooping);
MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source*pDataSource);
MA_API Me ma_data_source_set_range_in_pcm_frames(ma_data_source*pDataSource,M6 rangeBegInFrames,M6 rangeEndInFrames);
MA_API Mv ma_data_source_get_range_in_pcm_frames(const ma_data_source*pDataSource,M6*pRangeBegInFrames,M6*pRangeEndInFrames);
MA_API Me ma_data_source_set_loop_point_in_pcm_frames(ma_data_source*pDataSource,M6 loopBegInFrames,M6 loopEndInFrames);
MA_API Mv ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source*pDataSource,M6*pLoopBegInFrames,M6*pLoopEndInFrames);
MA_API Me ma_data_source_set_current(ma_data_source*pDataSource,ma_data_source*pCurrentDataSource);
MA_API ma_data_source*ma_data_source_get_current(const ma_data_source*pDataSource);
MA_API Me ma_data_source_set_next(ma_data_source*pDataSource,ma_data_source*pNextDataSource);
MA_API ma_data_source*ma_data_source_get_next(const ma_data_source*pDataSource);
MA_API Me ma_data_source_set_next_callback(ma_data_source*pDataSource,ma_data_source_get_next_proc onGetNext);
MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source*pDataSource);
typedef struct
{
ma_data_source_base ds;
ma_format format;
M3 Mh;
M3 sampleRate;
M6 cursor;
M6 sizeInFrames;
const Mv*pData;
} ma_audio_buffer_ref;
MA_API Me ma_audio_buffer_ref_init(ma_format format,M3 Mh,const Mv*pData,M6 sizeInFrames,ma_audio_buffer_ref*pAudioBufferRef);
MA_API Mv ma_audio_buffer_ref_uninit(ma_audio_buffer_ref*pAudioBufferRef);
MA_API Me ma_audio_buffer_ref_set_data(ma_audio_buffer_ref*pAudioBufferRef,const Mv*pData,M6 sizeInFrames);
MA_API M6 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref*pAudioBufferRef,Mv*pFramesOut,M6 frameCount,ma_bool32 loop);
MA_API Me ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref*pAudioBufferRef,M6 frameIndex);
MA_API Me ma_audio_buffer_ref_map(ma_audio_buffer_ref*pAudioBufferRef,Mv**ppFramesOut,M6*pFrameCount);
MA_API Me ma_audio_buffer_ref_unmap(ma_audio_buffer_ref*pAudioBufferRef,M6 frameCount);
MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref*pAudioBufferRef);
MA_API Me ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref*pAudioBufferRef,M6*pCursor);
MA_API Me ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref*pAudioBufferRef,M6*pLength);
MA_API Me ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref*pAudioBufferRef,M6*pAvailableFrames);
typedef struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
M6 sizeInFrames;
const Mv*pData;
ma_allocation_callbacks allocationCallbacks;
} ma_audio_buffer_config;
MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format,M3 Mh,M6 sizeInFrames,const Mv*pData,const ma_allocation_callbacks*pAllocationCallbacks);
typedef struct
{
ma_audio_buffer_ref ref;
ma_allocation_callbacks allocationCallbacks;
ma_bool32 ownsData;
ma_uint8 _pExtraData[1];
} ma_audio_buffer;
MA_API Me ma_audio_buffer_init(const ma_audio_buffer_config*Mo,ma_audio_buffer*pAudioBuffer);
MA_API Me ma_audio_buffer_init_copy(const ma_audio_buffer_config*Mo,ma_audio_buffer*pAudioBuffer);
MA_API Me ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config*Mo,ma_audio_buffer**ppAudioBuffer);
MA_API Mv ma_audio_buffer_uninit(ma_audio_buffer*pAudioBuffer);
MA_API Mv ma_audio_buffer_uninit_and_free(ma_audio_buffer*pAudioBuffer);
MA_API M6 ma_audio_buffer_read_pcm_frames(ma_audio_buffer*pAudioBuffer,Mv*pFramesOut,M6 frameCount,ma_bool32 loop);
MA_API Me ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer*pAudioBuffer,M6 frameIndex);
MA_API Me ma_audio_buffer_map(ma_audio_buffer*pAudioBuffer,Mv**ppFramesOut,M6*pFrameCount);
MA_API Me ma_audio_buffer_unmap(ma_audio_buffer*pAudioBuffer,M6 frameCount);
MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer*pAudioBuffer);
MA_API Me ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer*pAudioBuffer,M6*pCursor);
MA_API Me ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer*pAudioBuffer,M6*pLength);
MA_API Me ma_audio_buffer_get_available_frames(const ma_audio_buffer*pAudioBuffer,M6*pAvailableFrames);
typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page;
struct ma_paged_audio_buffer_page
{
MA_ATOMIC(MA_SIZEOF_PTR,ma_paged_audio_buffer_page*) pNext;
M6 sizeInFrames;
ma_uint8 pAudioData[1];
};
typedef struct
{
ma_format format;
M3 Mh;
ma_paged_audio_buffer_page head;
MA_ATOMIC(MA_SIZEOF_PTR,ma_paged_audio_buffer_page*) pTail;
} ma_paged_audio_buffer_data;
MA_API Me ma_paged_audio_buffer_data_init(ma_format format,M3 Mh,ma_paged_audio_buffer_data*pData);
MA_API Mv ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data*pData,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API ma_paged_audio_buffer_page*ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data*pData);
MA_API ma_paged_audio_buffer_page*ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data*pData);
MA_API Me ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data*pData,M6*pLength);
MA_API Me ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data*pData,M6 pageSizeInFrames,const Mv*pInitialData,const ma_allocation_callbacks*pAllocationCallbacks,ma_paged_audio_buffer_page**ppPage);
MA_API Me ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data*pData,ma_paged_audio_buffer_page*pPage,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data*pData,ma_paged_audio_buffer_page*pPage);
MA_API Me ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data*pData,M3 pageSizeInFrames,const Mv*pInitialData,const ma_allocation_callbacks*pAllocationCallbacks);
typedef struct
{
ma_paged_audio_buffer_data*pData;
} ma_paged_audio_buffer_config;
MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data*pData);
typedef struct
{
ma_data_source_base ds;
ma_paged_audio_buffer_data*pData;
ma_paged_audio_buffer_page*pCurrent;
M6 relativeCursor;
M6 absoluteCursor;
} ma_paged_audio_buffer;
MA_API Me ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config*Mo,ma_paged_audio_buffer*pPagedAudioBuffer);
MA_API Mv ma_paged_audio_buffer_uninit(ma_paged_audio_buffer*pPagedAudioBuffer);
MA_API Me ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer*pPagedAudioBuffer,Mv*pFramesOut,M6 frameCount,M6*pFramesRead);
MA_API Me ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer*pPagedAudioBuffer,M6 frameIndex);
MA_API Me ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer*pPagedAudioBuffer,M6*pCursor);
MA_API Me ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer*pPagedAudioBuffer,M6*pLength);
typedef struct
{
Mv*pBuffer;
M3 subbufferSizeInBytes;
M3 subbufferCount;
M3 subbufferStrideInBytes;
MA_ATOMIC(4,M3) encodedReadOffset;
MA_ATOMIC(4,M3) encodedWriteOffset;
ma_bool8 ownsBuffer;
ma_bool8 clearOnWriteAcquire;
ma_allocation_callbacks allocationCallbacks;
} ma_rb;
MA_API Me ma_rb_init_ex(size_t subbufferSizeInBytes,size_t subbufferCount,size_t subbufferStrideInBytes,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_rb*pRB);
MA_API Me ma_rb_init(size_t bufferSizeInBytes,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_rb*pRB);
MA_API Mv ma_rb_uninit(ma_rb*pRB);
MA_API Mv ma_rb_reset(ma_rb*pRB);
MA_API Me ma_rb_acquire_read(ma_rb*pRB,size_t*pSizeInBytes,Mv**ppBufferOut);
MA_API Me ma_rb_commit_read(ma_rb*pRB,size_t sizeInBytes);
MA_API Me ma_rb_acquire_write(ma_rb*pRB,size_t*pSizeInBytes,Mv**ppBufferOut);
MA_API Me ma_rb_commit_write(ma_rb*pRB,size_t sizeInBytes);
MA_API Me ma_rb_seek_read(ma_rb*pRB,size_t offsetInBytes);
MA_API Me ma_rb_seek_write(ma_rb*pRB,size_t offsetInBytes);
MA_API ma_int32 ma_rb_pointer_distance(ma_rb*pRB);
MA_API M3 ma_rb_available_read(ma_rb*pRB);
MA_API M3 ma_rb_available_write(ma_rb*pRB);
MA_API size_t ma_rb_get_subbuffer_size(ma_rb*pRB);
MA_API size_t ma_rb_get_subbuffer_stride(ma_rb*pRB);
MA_API size_t ma_rb_get_subbuffer_offset(ma_rb*pRB,size_t subbufferIndex);
MA_API Mv*ma_rb_get_subbuffer_ptr(ma_rb*pRB,size_t subbufferIndex,Mv*pBuffer);
typedef struct
{
ma_data_source_base ds;
ma_rb rb;
ma_format format;
M3 Mh;
M3 sampleRate;
} ma_pcm_rb;
MA_API Me ma_pcm_rb_init_ex(ma_format format,M3 Mh,M3 subbufferSizeInFrames,M3 subbufferCount,M3 subbufferStrideInFrames,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_pcm_rb*pRB);
MA_API Me ma_pcm_rb_init(ma_format format,M3 Mh,M3 bufferSizeInFrames,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_pcm_rb*pRB);
MA_API Mv ma_pcm_rb_uninit(ma_pcm_rb*pRB);
MA_API Mv ma_pcm_rb_reset(ma_pcm_rb*pRB);
MA_API Me ma_pcm_rb_acquire_read(ma_pcm_rb*pRB,M3*pSizeInFrames,Mv**ppBufferOut);
MA_API Me ma_pcm_rb_commit_read(ma_pcm_rb*pRB,M3 sizeInFrames);
MA_API Me ma_pcm_rb_acquire_write(ma_pcm_rb*pRB,M3*pSizeInFrames,Mv**ppBufferOut);
MA_API Me ma_pcm_rb_commit_write(ma_pcm_rb*pRB,M3 sizeInFrames);
MA_API Me ma_pcm_rb_seek_read(ma_pcm_rb*pRB,M3 offsetInFrames);
MA_API Me ma_pcm_rb_seek_write(ma_pcm_rb*pRB,M3 offsetInFrames);
MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_available_read(ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_available_write(ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb*pRB,M3 subbufferIndex);
MA_API Mv*ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb*pRB,M3 subbufferIndex,Mv*pBuffer);
MA_API ma_format ma_pcm_rb_get_format(const ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_get_channels(const ma_pcm_rb*pRB);
MA_API M3 ma_pcm_rb_get_sample_rate(const ma_pcm_rb*pRB);
MA_API Mv ma_pcm_rb_set_sample_rate(ma_pcm_rb*pRB,M3 sampleRate);
typedef struct
{
ma_pcm_rb rb;
} ma_duplex_rb;
MA_API Me ma_duplex_rb_init(ma_format captureFormat,M3 captureChannels,M3 sampleRate,M3 captureInternalSampleRate,M3 captureInternalPeriodSizeInFrames,const ma_allocation_callbacks*pAllocationCallbacks,ma_duplex_rb*pRB);
MA_API Me ma_duplex_rb_uninit(ma_duplex_rb*pRB);
MA_API const char*ma_result_description(Me Mf);
MA_API Mv*ma_malloc(size_t sz,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Mv*ma_calloc(size_t sz,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Mv*ma_realloc(Mv*p,size_t sz,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Mv ma_free(Mv*p,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Mv*ma_aligned_malloc(size_t sz,size_t alignment,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Mv ma_aligned_free(Mv*p,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API const char*ma_get_format_name(ma_format format);
MA_API Mv ma_blend_f32(float*pOut,float*pInA,float*pInB,float factor,M3 Mh);
MA_API M3 ma_get_bytes_per_sample(ma_format format);
static MA_INLINE M3 ma_get_bytes_per_frame(ma_format format,M3 Mh) { Mr ma_get_bytes_per_sample(format)*Mh; }
MA_API const char*ma_log_level_to_string(M3 logLevel);
MA_API Me ma_spinlock_lock(volatile ma_spinlock*pSpinlock);
MA_API Me ma_spinlock_lock_noyield(volatile ma_spinlock*pSpinlock);
MA_API Me ma_spinlock_unlock(volatile ma_spinlock*pSpinlock);
#ifndef MA_NO_THREADING
MA_API Me ma_mutex_init(ma_mutex*pMutex);
MA_API Mv ma_mutex_uninit(ma_mutex*pMutex);
MA_API Mv ma_mutex_lock(ma_mutex*pMutex);
MA_API Mv ma_mutex_unlock(ma_mutex*pMutex);
MA_API Me ma_event_init(ma_event*pEvent);
MA_API Mv ma_event_uninit(ma_event*pEvent);
MA_API Me ma_event_wait(ma_event*pEvent);
MA_API Me ma_event_signal(ma_event*pEvent);
MA_API Me ma_semaphore_init(int initialValue,ma_semaphore*pSemaphore);
MA_API Mv ma_semaphore_uninit(ma_semaphore*pSemaphore);
MA_API Me ma_semaphore_wait(ma_semaphore*pSemaphore);
MA_API Me ma_semaphore_release(ma_semaphore*pSemaphore);
#endif
typedef struct
{
#ifndef MA_NO_THREADING
ma_event e;
#endif
M3 counter;
} ma_fence;
MA_API Me ma_fence_init(ma_fence*pFence);
MA_API Mv ma_fence_uninit(ma_fence*pFence);
MA_API Me ma_fence_acquire(ma_fence*pFence);
MA_API Me ma_fence_release(ma_fence*pFence);
MA_API Me ma_fence_wait(ma_fence*pFence);
typedef Mv ma_async_notification;
typedef struct
{
Mv (*onSignal)(ma_async_notification*pNotification);
} ma_async_notification_callbacks;
MA_API Me ma_async_notification_signal(ma_async_notification*pNotification);
typedef struct
{
ma_async_notification_callbacks cb;
ma_bool32 signalled;
} ma_async_notification_poll;
MA_API Me ma_async_notification_poll_init(ma_async_notification_poll*pNotificationPoll);
MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll*pNotificationPoll);
typedef struct
{
ma_async_notification_callbacks cb;
#ifndef MA_NO_THREADING
ma_event e;
#endif
} ma_async_notification_event;
MA_API Me ma_async_notification_event_init(ma_async_notification_event*pNotificationEvent);
MA_API Me ma_async_notification_event_uninit(ma_async_notification_event*pNotificationEvent);
MA_API Me ma_async_notification_event_wait(ma_async_notification_event*pNotificationEvent);
MA_API Me ma_async_notification_event_signal(ma_async_notification_event*pNotificationEvent);
typedef struct
{
M3 capacity;
} ma_slot_allocator_config;
MA_API ma_slot_allocator_config ma_slot_allocator_config_init(M3 capacity);
typedef struct
{
MA_ATOMIC(4,M3) bitfield;
} ma_slot_allocator_group;
typedef struct
{
ma_slot_allocator_group*pGroups;
M3*pSlots;
M3 count;
M3 capacity;
ma_bool32 _ownsHeap;
Mv*_pHeap;
} ma_slot_allocator;
MA_API Me ma_slot_allocator_get_heap_size(const ma_slot_allocator_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_slot_allocator_init_preallocated(const ma_slot_allocator_config*Mo,Mv*pHeap,ma_slot_allocator*pAllocator);
MA_API Me ma_slot_allocator_init(const ma_slot_allocator_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_slot_allocator*pAllocator);
MA_API Mv ma_slot_allocator_uninit(ma_slot_allocator*pAllocator,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_slot_allocator_alloc(ma_slot_allocator*pAllocator,M6*pSlot);
MA_API Me ma_slot_allocator_free(ma_slot_allocator*pAllocator,M6 slot);
typedef struct ma_job ma_job;
typedef Me (*ma_job_proc)(ma_job*pJob);
typedef enum
{
MA_JOB_TYPE_QUIT=0,MA_JOB_TYPE_CUSTOM,MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE,MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE,MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE,MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_BUFFER,MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_BUFFER,MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM,MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM,MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_STREAM,MA_JOB_TYPE_RESOURCE_MANAGER_SEEK_DATA_STREAM,MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE,MA_JOB_TYPE_COUNT
} ma_job_type;
struct ma_job
{
union
{
struct
{
ma_uint16 code;
ma_uint16 slot;
M3 refcount;
} breakup;
M6 allocation;
} toc;
MA_ATOMIC(8,M6) next;
M3 order;
union
{
struct
{
ma_job_proc proc;
ma_uintptr data0;
ma_uintptr data1;
} custom;
union
{
struct
{ Mv*pResourceManager; Mv*pDataBufferNode;
char*pFilePath;
wchar_t*pFilePathW;
M3 flags;
ma_async_notification*pInitNotification;
ma_async_notification*pDoneNotification;
ma_fence*pInitFence;
ma_fence*pDoneFence;
} loadDataBufferNode;
struct
{ Mv*pResourceManager; Mv*pDataBufferNode;
ma_async_notification*pDoneNotification;
ma_fence*pDoneFence;
} freeDataBufferNode;
struct
{ Mv*pResourceManager; Mv*pDataBufferNode; Mv*pDecoder;
ma_async_notification*pDoneNotification;
ma_fence*pDoneFence;
} pageDataBufferNode;
struct
{ Mv*pDataBuffer;
ma_async_notification*pInitNotification;
ma_async_notification*pDoneNotification;
ma_fence*pInitFence;
ma_fence*pDoneFence;
M6 rangeBegInPCMFrames;
M6 rangeEndInPCMFrames;
M6 loopPointBegInPCMFrames;
M6 loopPointEndInPCMFrames;
M3 isLooping;
} loadDataBuffer;
struct
{ Mv*pDataBuffer;
ma_async_notification*pDoneNotification;
ma_fence*pDoneFence;
} freeDataBuffer;
struct
{ Mv*pDataStream;
char*pFilePath;
wchar_t*pFilePathW;
M6 initialSeekPoint;
ma_async_notification*pInitNotification;
ma_fence*pInitFence;
} loadDataStream;
struct
{ Mv*pDataStream;
ma_async_notification*pDoneNotification;
ma_fence*pDoneFence;
} freeDataStream;
struct
{ Mv*pDataStream;
M3 pageIndex;
} pageDataStream;
struct
{ Mv*pDataStream;
M6 frameIndex;
} seekDataStream;
} resourceManager;
union
{
union
{
struct
{ Mv*Md; M3 deviceType;
} reroute;
} aaudio;
} device;
} data;
};
MA_API ma_job ma_job_init(ma_uint16 code);
MA_API Me ma_job_process(ma_job*pJob);
typedef enum
{
MA_JOB_QUEUE_FLAG_NON_BLOCKING=0x00000001
} ma_job_queue_flags;
typedef struct
{
M3 flags;
M3 capacity;
} ma_job_queue_config;
MA_API ma_job_queue_config ma_job_queue_config_init(M3 flags,M3 capacity);
typedef struct
{
M3 flags;
M3 capacity;
MA_ATOMIC(8,M6) head;
MA_ATOMIC(8,M6) tail;
#ifndef MA_NO_THREADING
ma_semaphore sem;
#endif
ma_slot_allocator allocator;
ma_job*pJobs;
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock lock;
#endif
Mv*_pHeap;
ma_bool32 _ownsHeap;
} ma_job_queue;
MA_API Me ma_job_queue_get_heap_size(const ma_job_queue_config*Mo,size_t*pHeapSizeInBytes);
MA_API Me ma_job_queue_init_preallocated(const ma_job_queue_config*Mo,Mv*pHeap,ma_job_queue*pQueue);
MA_API Me ma_job_queue_init(const ma_job_queue_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_job_queue*pQueue);
MA_API Mv ma_job_queue_uninit(ma_job_queue*pQueue,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_job_queue_post(ma_job_queue*pQueue,const ma_job*pJob);
MA_API Me ma_job_queue_next(ma_job_queue*pQueue,ma_job*pJob);
#ifndef MA_NO_DEVICE_IO
#if defined(MA_WIN32)
#define MA_SUPPORT_WASAPI
#if defined(MA_WIN32_DESKTOP)
#define MA_SUPPORT_DSOUND
#define MA_SUPPORT_WINMM
#if !defined(__COSMOPOLITAN__)
#define MA_SUPPORT_JACK
#endif
#endif
#endif
#if defined(MA_UNIX)&&!defined(MA_ORBIS)&&!defined(MA_PROSPERO)
#if defined(MA_LINUX)
#if !defined(MA_ANDROID)&&!defined(__COSMOPOLITAN__)
#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(__OpenBSD__)
#define MA_SUPPORT_SNDIO
#endif
#if defined(__NetBSD__)||defined(__OpenBSD__)
#define MA_SUPPORT_AUDIO4
#endif
#if defined(__FreeBSD__)||defined(__DragonFly__)
#define MA_SUPPORT_OSS
#endif
#endif
#if defined(MA_ANDROID)
#define MA_SUPPORT_AAUDIO
#define MA_SUPPORT_OPENSL
#endif
#if defined(MA_APPLE)
#define MA_SUPPORT_COREAUDIO
#endif
#if defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_WEBAUDIO
#endif
#define MA_SUPPORT_CUSTOM
#if !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_NULL
#endif
#if defined(MA_SUPPORT_WASAPI)&&!defined(MA_NO_WASAPI)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_WASAPI))
#define MA_HAS_WASAPI
#endif
#if defined(MA_SUPPORT_DSOUND)&&!defined(MA_NO_DSOUND)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_DSOUND))
#define MA_HAS_DSOUND
#endif
#if defined(MA_SUPPORT_WINMM)&&!defined(MA_NO_WINMM)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_WINMM))
#define MA_HAS_WINMM
#endif
#if defined(MA_SUPPORT_ALSA)&&!defined(MA_NO_ALSA)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_ALSA))
#define MA_HAS_ALSA
#endif
#if defined(MA_SUPPORT_PULSEAUDIO)&&!defined(MA_NO_PULSEAUDIO)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_PULSEAUDIO))
#define MA_HAS_PULSEAUDIO
#endif
#if defined(MA_SUPPORT_JACK)&&!defined(MA_NO_JACK)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_JACK))
#define MA_HAS_JACK
#endif
#if defined(MA_SUPPORT_COREAUDIO)&&!defined(MA_NO_COREAUDIO)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_COREAUDIO))
#define MA_HAS_COREAUDIO
#endif
#if defined(MA_SUPPORT_SNDIO)&&!defined(MA_NO_SNDIO)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_SNDIO))
#define MA_HAS_SNDIO
#endif
#if defined(MA_SUPPORT_AUDIO4)&&!defined(MA_NO_AUDIO4)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_AUDIO4))
#define MA_HAS_AUDIO4
#endif
#if defined(MA_SUPPORT_OSS)&&!defined(MA_NO_OSS)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_OSS))
#define MA_HAS_OSS
#endif
#if defined(MA_SUPPORT_AAUDIO)&&!defined(MA_NO_AAUDIO)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_AAUDIO))
#define MA_HAS_AAUDIO
#endif
#if defined(MA_SUPPORT_OPENSL)&&!defined(MA_NO_OPENSL)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_OPENSL))
#define MA_HAS_OPENSL
#endif
#if defined(MA_SUPPORT_WEBAUDIO)&&!defined(MA_NO_WEBAUDIO)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_WEBAUDIO))
#define MA_HAS_WEBAUDIO
#endif
#if defined(MA_SUPPORT_CUSTOM)&&!defined(MA_NO_CUSTOM)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_CUSTOM))
#define MA_HAS_CUSTOM
#endif
#if defined(MA_SUPPORT_NULL)&&!defined(MA_NO_NULL)&&(!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS)||defined(MA_ENABLE_NULL))
#define MA_HAS_NULL
#endif
typedef enum
{
ma_device_state_uninitialized=0,ma_device_state_stopped=1,ma_device_state_started=2,ma_device_state_starting=3,ma_device_state_stopping=4
} ma_device_state;
MA_ATOMIC_SAFE_TYPE_DECL(i32,4,device_state)
#ifdef MA_SUPPORT_WASAPI
typedef struct
{
Mv*lpVtbl;
M3 counter;
ma_device*Md;
} ma_IMMNotificationClient;
#endif
typedef enum
{
ma_backend_wasapi,ma_backend_dsound,ma_backend_winmm,ma_backend_coreaudio,ma_backend_sndio,ma_backend_audio4,ma_backend_oss,ma_backend_pulseaudio,ma_backend_alsa,ma_backend_jack,ma_backend_aaudio,ma_backend_opensl,ma_backend_webaudio,ma_backend_custom,ma_backend_null
} ma_backend;
#define MA_BACKEND_COUNT (ma_backend_null+1)
typedef struct
{
ma_bool32 noThread;
M3 jobQueueCapacity;
M3 jobQueueFlags;
} ma_device_job_thread_config;
MA_API ma_device_job_thread_config ma_device_job_thread_config_init(Mv);
typedef struct
{
ma_thread thread;
ma_job_queue jobQueue;
ma_bool32 _hasThread;
} ma_device_job_thread;
MA_API Me ma_device_job_thread_init(const ma_device_job_thread_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_device_job_thread*pJobThread);
MA_API Mv ma_device_job_thread_uninit(ma_device_job_thread*pJobThread,const ma_allocation_callbacks*pAllocationCallbacks);
MA_API Me ma_device_job_thread_post(ma_device_job_thread*pJobThread,const ma_job*pJob);
MA_API Me ma_device_job_thread_next(ma_device_job_thread*pJobThread,ma_job*pJob);
typedef enum
{
ma_device_notification_type_started,ma_device_notification_type_stopped,ma_device_notification_type_rerouted,ma_device_notification_type_interruption_began,ma_device_notification_type_interruption_ended,ma_device_notification_type_unlocked
} ma_device_notification_type;
typedef struct
{
ma_device*Md;
ma_device_notification_type type;
union
{
struct
{
int _unused;
} started;
struct
{
int _unused;
} stopped;
struct
{
int _unused;
} rerouted;
struct
{
int _unused;
} interruption;
} data;
} ma_device_notification;
typedef Mv (*ma_device_notification_proc)(const ma_device_notification*pNotification);
typedef Mv (*ma_device_data_proc)(ma_device*Md,Mv*pOutput,const Mv*pInput,M3 frameCount);
typedef Mv (*ma_stop_proc)(ma_device*Md);
typedef enum
{
Mt=1,ma_device_type_capture=2,ma_device_type_duplex=Mt|ma_device_type_capture,ma_device_type_loopback=4
} ma_device_type;
typedef enum
{
ma_share_mode_shared=0,ma_share_mode_exclusive
} ma_share_mode;
typedef enum
{
ma_ios_session_category_default=0,ma_ios_session_category_none,ma_ios_session_category_ambient,ma_ios_session_category_solo_ambient,ma_ios_session_category_playback,ma_ios_session_category_record,ma_ios_session_category_play_and_record,ma_ios_session_category_multi_route
} ma_ios_session_category;
typedef enum
{
ma_ios_session_category_option_mix_with_others=0x01,ma_ios_session_category_option_duck_others=0x02,ma_ios_session_category_option_allow_bluetooth=0x04,ma_ios_session_category_option_default_to_speaker=0x08,ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others=0x11,ma_ios_session_category_option_allow_bluetooth_a2dp=0x20,ma_ios_session_category_option_allow_air_play=0x40,} ma_ios_session_category_option;
typedef enum
{
ma_opensl_stream_type_default=0,ma_opensl_stream_type_voice,ma_opensl_stream_type_system,ma_opensl_stream_type_ring,ma_opensl_stream_type_media,ma_opensl_stream_type_alarm,ma_opensl_stream_type_notification
} ma_opensl_stream_type;
typedef enum
{
ma_opensl_recording_preset_default=0,ma_opensl_recording_preset_generic,ma_opensl_recording_preset_camcorder,ma_opensl_recording_preset_voice_recognition,ma_opensl_recording_preset_voice_communication,ma_opensl_recording_preset_voice_unprocessed
} ma_opensl_recording_preset;
typedef enum
{
ma_wasapi_usage_default=0,ma_wasapi_usage_games,ma_wasapi_usage_pro_audio,} ma_wasapi_usage;
typedef enum
{
ma_aaudio_usage_default=0,ma_aaudio_usage_media,ma_aaudio_usage_voice_communication,ma_aaudio_usage_voice_communication_signalling,ma_aaudio_usage_alarm,ma_aaudio_usage_notification,ma_aaudio_usage_notification_ringtone,ma_aaudio_usage_notification_event,ma_aaudio_usage_assistance_accessibility,ma_aaudio_usage_assistance_navigation_guidance,ma_aaudio_usage_assistance_sonification,ma_aaudio_usage_game,ma_aaudio_usage_assitant,ma_aaudio_usage_emergency,ma_aaudio_usage_safety,ma_aaudio_usage_vehicle_status,ma_aaudio_usage_announcement
} ma_aaudio_usage;
typedef enum
{
ma_aaudio_content_type_default=0,ma_aaudio_content_type_speech,ma_aaudio_content_type_music,ma_aaudio_content_type_movie,ma_aaudio_content_type_sonification
} ma_aaudio_content_type;
typedef enum
{
ma_aaudio_input_preset_default=0,ma_aaudio_input_preset_generic,ma_aaudio_input_preset_camcorder,ma_aaudio_input_preset_voice_recognition,ma_aaudio_input_preset_voice_communication,ma_aaudio_input_preset_unprocessed,ma_aaudio_input_preset_voice_performance
} ma_aaudio_input_preset;
typedef enum
{
ma_aaudio_allow_capture_default=0,ma_aaudio_allow_capture_by_all,ma_aaudio_allow_capture_by_system,ma_aaudio_allow_capture_by_none
} ma_aaudio_allowed_capture_policy;
typedef union
{
ma_int64 counter;
double counterD;
} ma_timer;
typedef union
{
ma_wchar_win32 wasapi[64];
ma_uint8 dsound[16]; M3 winmm;
char alsa[256];
char pulse[256];
int jack;
char coreaudio[256];
char sndio[256];
char audio4[256];
char oss[64];
ma_int32 aaudio;
M3 opensl;
char webaudio[32];
union
{
int i;
char s[256];
Mv*p;
} custom;
int nullbackend;
} ma_device_id;
MA_API ma_bool32 ma_device_id_equal(const ma_device_id*pA,const ma_device_id*pB);
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)
#ifndef MA_MAX_DEVICE_NAME_LENGTH
#define MA_MAX_DEVICE_NAME_LENGTH 255
#endif
typedef struct
{
ma_device_id id;
char name[MA_MAX_DEVICE_NAME_LENGTH+1];
ma_bool32 isDefault;
M3 nativeDataFormatCount;
struct
{
ma_format format;
M3 Mh;
M3 sampleRate;
M3 flags;
} nativeDataFormats[ 64];
} ma_device_info;
struct ma_device_config
{
ma_device_type deviceType;
M3 sampleRate;
M3 periodSizeInFrames;
M3 periodSizeInMilliseconds;
M3 periods;
ma_performance_profile performanceProfile;
ma_bool8 noPreSilencedOutputBuffer;
ma_bool8 noClip;
ma_bool8 noDisableDenormals;
ma_bool8 noFixedSizedCallback;
ma_device_data_proc dataCallback;
ma_device_notification_proc notificationCallback;
ma_stop_proc stopCallback;
Mv*pUserData;
ma_resampler_config resampling;
struct
{
const ma_device_id*pDeviceID;
ma_format format;
M3 Mh;
ma_channel*pChannelMap;
ma_channel_mix_mode channelMixMode;
ma_bool32 calculateLFEFromSpatialChannels;
ma_share_mode shareMode;
} playback;
struct
{
const ma_device_id*pDeviceID;
ma_format format;
M3 Mh;
ma_channel*pChannelMap;
ma_channel_mix_mode channelMixMode;
ma_bool32 calculateLFEFromSpatialChannels;
ma_share_mode shareMode;
} capture;
struct
{
ma_wasapi_usage usage;
ma_bool8 noAutoConvertSRC;
ma_bool8 noDefaultQualitySRC;
ma_bool8 noAutoStreamRouting;
ma_bool8 noHardwareOffloading;
M3 loopbackProcessID;
ma_bool8 loopbackProcessExclude;
} wasapi;
struct
{
ma_bool32 noMMap;
ma_bool32 noAutoFormat;
ma_bool32 noAutoChannels;
ma_bool32 noAutoResample;
} alsa;
struct
{
const char*pStreamNamePlayback;
const char*pStreamNameCapture;
int channelMap;
} pulse;
struct
{
ma_bool32 allowNominalSampleRateChange;
} coreaudio;
struct
{
ma_opensl_stream_type streamType;
ma_opensl_recording_preset recordingPreset;
ma_bool32 enableCompatibilityWorkarounds;
} opensl;
struct
{
ma_aaudio_usage usage;
ma_aaudio_content_type contentType;
ma_aaudio_input_preset inputPreset;
ma_aaudio_allowed_capture_policy allowedCapturePolicy;
ma_bool32 noAutoStartAfterReroute;
ma_bool32 enableCompatibilityWorkarounds;
ma_bool32 allowSetBufferCapacity;
} aaudio;
};
typedef ma_bool32 (*ma_enum_devices_callback_proc)(ma_context*Mc,ma_device_type deviceType,const ma_device_info*pInfo,Mv*pUserData);
typedef struct
{
const ma_device_id*pDeviceID;
ma_share_mode shareMode;
ma_format format;
M3 Mh;
M3 sampleRate;
ma_channel channelMap[MA_MAX_CHANNELS];
M3 periodSizeInFrames;
M3 periodSizeInMilliseconds;
M3 periodCount;
} ma_device_descriptor;
struct ma_backend_callbacks
{
Me (*onContextInit)(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks);
Me (*onContextUninit)(ma_context*Mc);
Me (*onContextEnumerateDevices)(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData);
Me (*onContextGetDeviceInfo)(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo);
Me (*onDeviceInit)(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture);
Me (*onDeviceUninit)(ma_device*Md);
Me (*onDeviceStart)(ma_device*Md);
Me (*onDeviceStop)(ma_device*Md);
Me (*onDeviceRead)(ma_device*Md,Mv*pFrames,M3 frameCount,M3*pFramesRead);
Me (*onDeviceWrite)(ma_device*Md,const Mv*pFrames,M3 frameCount,M3*pFramesWritten);
Me (*onDeviceDataLoop)(ma_device*Md);
Me (*onDeviceDataLoopWakeup)(ma_device*Md);
Me (*onDeviceGetInfo)(ma_device*Md,ma_device_type type,ma_device_info*pDeviceInfo);
};
struct ma_context_config
{
ma_log*pLog;
ma_thread_priority threadPriority;
size_t threadStackSize;
Mv*pUserData;
ma_allocation_callbacks allocationCallbacks;
struct
{
ma_handle hWnd;
} dsound;
struct
{
ma_bool32 useVerboseDeviceEnumeration;
} alsa;
struct
{
const char*pApplicationName;
const char*pServerName;
ma_bool32 tryAutoSpawn;
} pulse;
struct
{
ma_ios_session_category sessionCategory;
M3 sessionCategoryOptions;
ma_bool32 noAudioSessionActivate;
ma_bool32 noAudioSessionDeactivate;
} coreaudio;
struct
{
const char*pClientName;
ma_bool32 tryStartServer;
} jack;
ma_backend_callbacks custom;
};
typedef struct
{
int code;
ma_event*pEvent;
union
{
struct
{
int _unused;
} quit;
struct
{
ma_device_type deviceType;
Mv*pAudioClient;
Mv**ppAudioClientService;
Me*pResult;
} createAudioClient;
struct
{
ma_device*Md;
ma_device_type deviceType;
} releaseAudioClient;
} data;
} ma_context_command__wasapi;
struct ma_context
{
ma_backend_callbacks callbacks;
ma_backend backend;
ma_log*pLog;
ma_log log;
ma_thread_priority threadPriority;
size_t threadStackSize;
Mv*pUserData;
ma_allocation_callbacks allocationCallbacks;
ma_mutex deviceEnumLock;
ma_mutex deviceInfoLock;
M3 deviceInfoCapacity;
M3 playbackDeviceInfoCount;
M3 captureDeviceInfoCount;
ma_device_info*pDeviceInfos;
union
{
#ifdef MA_SUPPORT_WASAPI
struct
{
ma_thread commandThread;
ma_mutex commandLock;
ma_semaphore commandSem;
M3 commandIndex;
M3 commandCount;
ma_context_command__wasapi commands[4];
ma_handle hAvrt;
ma_proc AvSetMmThreadCharacteristicsA;
ma_proc AvRevertMmThreadcharacteristics;
ma_handle hMMDevapi;
ma_proc ActivateAudioInterfaceAsync;
} wasapi;
#endif
#ifdef MA_SUPPORT_DSOUND
struct
{
ma_handle hWnd;
ma_handle hDSoundDLL;
ma_proc DirectSoundCreate;
ma_proc DirectSoundEnumerateA;
ma_proc DirectSoundCaptureCreate;
ma_proc DirectSoundCaptureEnumerateA;
} dsound;
#endif
#ifdef MA_SUPPORT_WINMM
struct
{
ma_handle hWinMM;
ma_proc waveOutGetNumDevs;
ma_proc waveOutGetDevCapsA;
ma_proc waveOutOpen;
ma_proc waveOutClose;
ma_proc waveOutPrepareHeader;
ma_proc waveOutUnprepareHeader;
ma_proc waveOutWrite;
ma_proc waveOutReset;
ma_proc waveInGetNumDevs;
ma_proc waveInGetDevCapsA;
ma_proc waveInOpen;
ma_proc waveInClose;
ma_proc waveInPrepareHeader;
ma_proc waveInUnprepareHeader;
ma_proc waveInAddBuffer;
ma_proc waveInStart;
ma_proc waveInReset;
} winmm;
#endif
#ifdef MA_SUPPORT_ALSA
struct
{
ma_handle asoundSO;
ma_proc snd_pcm_open;
ma_proc snd_pcm_close;
ma_proc snd_pcm_hw_params_sizeof;
ma_proc snd_pcm_hw_params_any;
ma_proc snd_pcm_hw_params_set_format;
ma_proc snd_pcm_hw_params_set_format_first;
ma_proc snd_pcm_hw_params_get_format_mask;
ma_proc snd_pcm_hw_params_set_channels;
ma_proc snd_pcm_hw_params_set_channels_near;
ma_proc snd_pcm_hw_params_set_channels_minmax;
ma_proc snd_pcm_hw_params_set_rate_resample;
ma_proc snd_pcm_hw_params_set_rate;
ma_proc snd_pcm_hw_params_set_rate_near;
ma_proc snd_pcm_hw_params_set_buffer_size_near;
ma_proc snd_pcm_hw_params_set_periods_near;
ma_proc snd_pcm_hw_params_set_access;
ma_proc snd_pcm_hw_params_get_format;
ma_proc snd_pcm_hw_params_get_channels;
ma_proc snd_pcm_hw_params_get_channels_min;
ma_proc snd_pcm_hw_params_get_channels_max;
ma_proc snd_pcm_hw_params_get_rate;
ma_proc snd_pcm_hw_params_get_rate_min;
ma_proc snd_pcm_hw_params_get_rate_max;
ma_proc snd_pcm_hw_params_get_buffer_size;
ma_proc snd_pcm_hw_params_get_periods;
ma_proc snd_pcm_hw_params_get_access;
ma_proc snd_pcm_hw_params_test_format;
ma_proc snd_pcm_hw_params_test_channels;
ma_proc snd_pcm_hw_params_test_rate;
ma_proc snd_pcm_hw_params;
ma_proc snd_pcm_sw_params_sizeof;
ma_proc snd_pcm_sw_params_current;
ma_proc snd_pcm_sw_params_get_boundary;
ma_proc snd_pcm_sw_params_set_avail_min;
ma_proc snd_pcm_sw_params_set_start_threshold;
ma_proc snd_pcm_sw_params_set_stop_threshold;
ma_proc snd_pcm_sw_params;
ma_proc snd_pcm_format_mask_sizeof;
ma_proc snd_pcm_format_mask_test;
ma_proc snd_pcm_get_chmap;
ma_proc snd_pcm_state;
ma_proc snd_pcm_prepare;
ma_proc snd_pcm_start;
ma_proc snd_pcm_drop;
ma_proc snd_pcm_drain;
ma_proc snd_pcm_reset;
ma_proc snd_device_name_hint;
ma_proc snd_device_name_get_hint;
ma_proc snd_card_get_index;
ma_proc snd_device_name_free_hint;
ma_proc snd_pcm_mmap_begin;
ma_proc snd_pcm_mmap_commit;
ma_proc snd_pcm_recover;
ma_proc snd_pcm_readi;
ma_proc snd_pcm_writei;
ma_proc snd_pcm_avail;
ma_proc snd_pcm_avail_update;
ma_proc snd_pcm_wait;
ma_proc snd_pcm_nonblock;
ma_proc snd_pcm_info;
ma_proc snd_pcm_info_sizeof;
ma_proc snd_pcm_info_get_name;
ma_proc snd_pcm_poll_descriptors;
ma_proc snd_pcm_poll_descriptors_count;
ma_proc snd_pcm_poll_descriptors_revents;
ma_proc snd_config_update_free_global;
ma_mutex internalDeviceEnumLock;
ma_bool32 useVerboseDeviceEnumeration;
} alsa;
#endif
#ifdef MA_SUPPORT_PULSEAUDIO
struct
{
ma_handle pulseSO;
ma_proc pa_mainloop_new;
ma_proc pa_mainloop_free;
ma_proc pa_mainloop_quit;
ma_proc pa_mainloop_get_api;
ma_proc pa_mainloop_iterate;
ma_proc pa_mainloop_wakeup;
ma_proc pa_threaded_mainloop_new;
ma_proc pa_threaded_mainloop_free;
ma_proc pa_threaded_mainloop_start;
ma_proc pa_threaded_mainloop_stop;
ma_proc pa_threaded_mainloop_lock;
ma_proc pa_threaded_mainloop_unlock;
ma_proc pa_threaded_mainloop_wait;
ma_proc pa_threaded_mainloop_signal;
ma_proc pa_threaded_mainloop_accept;
ma_proc pa_threaded_mainloop_get_retval;
ma_proc pa_threaded_mainloop_get_api;
ma_proc pa_threaded_mainloop_in_thread;
ma_proc pa_threaded_mainloop_set_name;
ma_proc pa_context_new;
ma_proc pa_context_unref;
ma_proc pa_context_connect;
ma_proc pa_context_disconnect;
ma_proc pa_context_set_state_callback;
ma_proc pa_context_get_state;
ma_proc pa_context_get_sink_info_list;
ma_proc pa_context_get_source_info_list;
ma_proc pa_context_get_sink_info_by_name;
ma_proc pa_context_get_source_info_by_name;
ma_proc pa_operation_unref;
ma_proc pa_operation_get_state;
ma_proc pa_channel_map_init_extend;
ma_proc pa_channel_map_valid;
ma_proc pa_channel_map_compatible;
ma_proc pa_stream_new;
ma_proc pa_stream_unref;
ma_proc pa_stream_connect_playback;
ma_proc pa_stream_connect_record;
ma_proc pa_stream_disconnect;
ma_proc pa_stream_get_state;
ma_proc pa_stream_get_sample_spec;
ma_proc pa_stream_get_channel_map;
ma_proc pa_stream_get_buffer_attr;
ma_proc pa_stream_set_buffer_attr;
ma_proc pa_stream_get_device_name;
ma_proc pa_stream_set_write_callback;
ma_proc pa_stream_set_read_callback;
ma_proc pa_stream_set_suspended_callback;
ma_proc pa_stream_set_moved_callback;
ma_proc pa_stream_is_suspended;
ma_proc pa_stream_flush;
ma_proc pa_stream_drain;
ma_proc pa_stream_is_corked;
ma_proc pa_stream_cork;
ma_proc pa_stream_trigger;
ma_proc pa_stream_begin_write;
ma_proc pa_stream_write;
ma_proc pa_stream_peek;
ma_proc pa_stream_drop;
ma_proc pa_stream_writable_size;
ma_proc pa_stream_readable_size; ma_ptr pMainLoop; ma_ptr pPulseContext;
char*pApplicationName;
char*pServerName;
} pulse;
#endif
#ifdef MA_SUPPORT_JACK
struct
{
ma_handle jackSO;
ma_proc jack_client_open;
ma_proc jack_client_close;
ma_proc jack_client_name_size;
ma_proc jack_set_process_callback;
ma_proc jack_set_buffer_size_callback;
ma_proc jack_on_shutdown;
ma_proc jack_get_sample_rate;
ma_proc jack_get_buffer_size;
ma_proc jack_get_ports;
ma_proc jack_activate;
ma_proc jack_deactivate;
ma_proc jack_connect;
ma_proc jack_port_register;
ma_proc jack_port_name;
ma_proc jack_port_get_buffer;
ma_proc jack_free;
char*pClientName;
ma_bool32 tryStartServer;
} jack;
#endif
#ifdef MA_SUPPORT_COREAUDIO
struct
{
ma_handle hCoreFoundation;
ma_proc CFStringGetCString;
ma_proc CFRelease;
ma_handle hCoreAudio;
ma_proc AudioObjectGetPropertyData;
ma_proc AudioObjectGetPropertyDataSize;
ma_proc AudioObjectSetPropertyData;
ma_proc AudioObjectAddPropertyListener;
ma_proc AudioObjectRemovePropertyListener;
ma_handle hAudioUnit;
ma_proc AudioComponentFindNext;
ma_proc AudioComponentInstanceDispose;
ma_proc AudioComponentInstanceNew;
ma_proc AudioOutputUnitStart;
ma_proc AudioOutputUnitStop;
ma_proc AudioUnitAddPropertyListener;
ma_proc AudioUnitGetPropertyInfo;
ma_proc AudioUnitGetProperty;
ma_proc AudioUnitSetProperty;
ma_proc AudioUnitInitialize;
ma_proc AudioUnitRender; ma_ptr component;
ma_bool32 noAudioSessionDeactivate;
} coreaudio;
#endif
#ifdef MA_SUPPORT_SNDIO
struct
{
ma_handle sndioSO;
ma_proc sio_open;
ma_proc sio_close;
ma_proc sio_setpar;
ma_proc sio_getpar;
ma_proc sio_getcap;
ma_proc sio_start;
ma_proc sio_stop;
ma_proc sio_read;
ma_proc sio_write;
ma_proc sio_onmove;
ma_proc sio_nfds;
ma_proc sio_pollfd;
ma_proc sio_revents;
ma_proc sio_eof;
ma_proc sio_setvol;
ma_proc sio_onvol;
ma_proc sio_initpar;
} sndio;
#endif
#ifdef MA_SUPPORT_AUDIO4
struct
{
int _unused;
} audio4;
#endif
#ifdef MA_SUPPORT_OSS
struct
{
int versionMajor;
int versionMinor;
} oss;
#endif
#ifdef MA_SUPPORT_AAUDIO
struct
{
ma_handle hAAudio;
ma_proc AAudio_createStreamBuilder;
ma_proc AAudioStreamBuilder_delete;
ma_proc AAudioStreamBuilder_setDeviceId;
ma_proc AAudioStreamBuilder_setDirection;
ma_proc AAudioStreamBuilder_setSharingMode;
ma_proc AAudioStreamBuilder_setFormat;
ma_proc AAudioStreamBuilder_setChannelCount;
ma_proc AAudioStreamBuilder_setSampleRate;
ma_proc AAudioStreamBuilder_setBufferCapacityInFrames;
ma_proc AAudioStreamBuilder_setFramesPerDataCallback;
ma_proc AAudioStreamBuilder_setDataCallback;
ma_proc AAudioStreamBuilder_setErrorCallback;
ma_proc AAudioStreamBuilder_setPerformanceMode;
ma_proc AAudioStreamBuilder_setUsage;
ma_proc AAudioStreamBuilder_setContentType;
ma_proc AAudioStreamBuilder_setInputPreset;
ma_proc AAudioStreamBuilder_setAllowedCapturePolicy;
ma_proc AAudioStreamBuilder_openStream;
ma_proc AAudioStream_close;
ma_proc AAudioStream_getState;
ma_proc AAudioStream_waitForStateChange;
ma_proc AAudioStream_getFormat;
ma_proc AAudioStream_getChannelCount;
ma_proc AAudioStream_getSampleRate;
ma_proc AAudioStream_getBufferCapacityInFrames;
ma_proc AAudioStream_getFramesPerDataCallback;
ma_proc AAudioStream_getFramesPerBurst;
ma_proc AAudioStream_requestStart;
ma_proc AAudioStream_requestStop;
ma_device_job_thread jobThread;
} aaudio;
#endif
#ifdef MA_SUPPORT_OPENSL
struct
{
ma_handle libOpenSLES;
ma_handle SL_IID_ENGINE;
ma_handle SL_IID_AUDIOIODEVICECAPABILITIES;
ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
ma_handle SL_IID_RECORD;
ma_handle SL_IID_PLAY;
ma_handle SL_IID_OUTPUTMIX;
ma_handle SL_IID_ANDROIDCONFIGURATION;
ma_proc slCreateEngine;
} opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
struct
{
int _unused;
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
int _unused;
} null_backend;
#endif
};
union
{
#if defined(MA_WIN32)
struct
{ ma_handle hOle32DLL;
ma_proc CoInitialize;
ma_proc CoInitializeEx;
ma_proc CoUninitialize;
ma_proc CoCreateInstance;
ma_proc CoTaskMemFree;
ma_proc PropVariantClear;
ma_proc StringFromGUID2; ma_handle hUser32DLL;
ma_proc GetForegroundWindow;
ma_proc GetDesktopWindow; ma_handle hAdvapi32DLL;
ma_proc RegOpenKeyExA;
ma_proc RegCloseKey;
ma_proc RegQueryValueExA; long CoInitializeResult;
} win32;
#endif
#ifdef MA_POSIX
struct
{
int _unused;
} posix;
#endif
int _unused;
};
};
struct ma_device
{
ma_context*Mc;
ma_device_type type;
M3 sampleRate;
ma_atomic_device_state state;
ma_device_data_proc onData;
ma_device_notification_proc onNotification;
ma_stop_proc onStop;
Mv*pUserData;
ma_mutex startStopLock;
ma_event wakeupEvent;
ma_event startEvent;
ma_event stopEvent;
ma_thread thread;
Me workResult;
ma_bool8 isOwnerOfContext;
ma_bool8 noPreSilencedOutputBuffer;
ma_bool8 noClip;
ma_bool8 noDisableDenormals;
ma_bool8 noFixedSizedCallback;
ma_atomic_float masterVolumeFactor;
ma_duplex_rb duplexRB;
struct
{
ma_resample_algorithm algorithm;
ma_resampling_backend_vtable*pBackendVTable;
Mv*pBackendUserData;
struct
{
M3 lpfOrder;
} linear;
} resampling;
struct
{
ma_device_id*pID;
ma_device_id id;
char name[MA_MAX_DEVICE_NAME_LENGTH+1];
ma_share_mode shareMode;
ma_format format;
M3 Mh;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_format internalFormat;
M3 internalChannels;
M3 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
M3 internalPeriodSizeInFrames;
M3 internalPeriods;
ma_channel_mix_mode channelMixMode;
ma_bool32 calculateLFEFromSpatialChannels;
ma_data_converter converter;
Mv*pIntermediaryBuffer;
M3 intermediaryBufferCap;
M3 intermediaryBufferLen;
Mv*pInputCache;
M6 inputCacheCap;
M6 inputCacheConsumed;
M6 inputCacheRemaining;
} playback;
struct
{
ma_device_id*pID;
ma_device_id id;
char name[MA_MAX_DEVICE_NAME_LENGTH+1];
ma_share_mode shareMode;
ma_format format;
M3 Mh;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_format internalFormat;
M3 internalChannels;
M3 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
M3 internalPeriodSizeInFrames;
M3 internalPeriods;
ma_channel_mix_mode channelMixMode;
ma_bool32 calculateLFEFromSpatialChannels;
ma_data_converter converter;
Mv*pIntermediaryBuffer;
M3 intermediaryBufferCap;
M3 intermediaryBufferLen;
} capture;
union
{
#ifdef MA_SUPPORT_WASAPI
struct
{ ma_ptr pAudioClientPlayback; ma_ptr pAudioClientCapture; ma_ptr pRenderClient; ma_ptr pCaptureClient; ma_ptr pDeviceEnumerator;
ma_IMMNotificationClient notificationClient; ma_handle hEventPlayback; ma_handle hEventCapture;
M3 actualBufferSizeInFramesPlayback;
M3 actualBufferSizeInFramesCapture;
M3 originalPeriodSizeInFrames;
M3 originalPeriodSizeInMilliseconds;
M3 originalPeriods;
ma_performance_profile originalPerformanceProfile;
M3 periodSizeInFramesPlayback;
M3 periodSizeInFramesCapture;
Mv*pMappedBufferCapture;
M3 mappedBufferCaptureCap;
M3 mappedBufferCaptureLen;
Mv*pMappedBufferPlayback;
M3 mappedBufferPlaybackCap;
M3 mappedBufferPlaybackLen;
ma_atomic_bool32 isStartedCapture;
ma_atomic_bool32 isStartedPlayback;
M3 loopbackProcessID;
ma_bool8 loopbackProcessExclude;
ma_bool8 noAutoConvertSRC;
ma_bool8 noDefaultQualitySRC;
ma_bool8 noHardwareOffloading;
ma_bool8 allowCaptureAutoStreamRouting;
ma_bool8 allowPlaybackAutoStreamRouting;
ma_bool8 isDetachedPlayback;
ma_bool8 isDetachedCapture;
ma_wasapi_usage usage;
Mv*hAvrtHandle;
ma_mutex rerouteLock;
} wasapi;
#endif
#ifdef MA_SUPPORT_DSOUND
struct
{ ma_ptr pPlayback; ma_ptr pPlaybackPrimaryBuffer; ma_ptr pPlaybackBuffer; ma_ptr pCapture; ma_ptr pCaptureBuffer;
} dsound;
#endif
#ifdef MA_SUPPORT_WINMM
struct
{ ma_handle hDevicePlayback; ma_handle hDeviceCapture; ma_handle hEventPlayback; ma_handle hEventCapture;
M3 fragmentSizeInFrames;
M3 iNextHeaderPlayback;
M3 iNextHeaderCapture;
M3 headerFramesConsumedPlayback;
M3 headerFramesConsumedCapture; ma_uint8*pWAVEHDRPlayback; ma_uint8*pWAVEHDRCapture;
ma_uint8*pIntermediaryBufferPlayback;
ma_uint8*pIntermediaryBufferCapture;
ma_uint8*_pHeapData;
} winmm;
#endif
#ifdef MA_SUPPORT_ALSA
struct
{ ma_ptr pPCMPlayback; ma_ptr pPCMCapture; Mv*pPollDescriptorsPlayback; Mv*pPollDescriptorsCapture;
int pollDescriptorCountPlayback;
int pollDescriptorCountCapture;
int wakeupfdPlayback;
int wakeupfdCapture;
ma_bool8 isUsingMMapPlayback;
ma_bool8 isUsingMMapCapture;
} alsa;
#endif
#ifdef MA_SUPPORT_PULSEAUDIO
struct
{ ma_ptr pMainLoop; ma_ptr pPulseContext; ma_ptr pStreamPlayback; ma_ptr pStreamCapture;
} pulse;
#endif
#ifdef MA_SUPPORT_JACK
struct
{ ma_ptr pClient; ma_ptr*ppPortsPlayback; ma_ptr*ppPortsCapture;
float*pIntermediaryBufferPlayback;
float*pIntermediaryBufferCapture;
} jack;
#endif
#ifdef MA_SUPPORT_COREAUDIO
struct
{
M3 deviceObjectIDPlayback;
M3 deviceObjectIDCapture; ma_ptr audioUnitPlayback; ma_ptr audioUnitCapture; ma_ptr pAudioBufferList;
M3 audioBufferCapInFrames;
ma_event stopEvent;
M3 originalPeriodSizeInFrames;
M3 originalPeriodSizeInMilliseconds;
M3 originalPeriods;
ma_performance_profile originalPerformanceProfile;
ma_bool32 isDefaultPlaybackDevice;
ma_bool32 isDefaultCaptureDevice;
ma_bool32 isSwitchingPlaybackDevice;
ma_bool32 isSwitchingCaptureDevice;
Mv*pNotificationHandler;
} coreaudio;
#endif
#ifdef MA_SUPPORT_SNDIO
struct
{
ma_ptr handlePlayback;
ma_ptr handleCapture;
ma_bool32 isStartedPlayback;
ma_bool32 isStartedCapture;
} 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
{ ma_ptr pStreamPlayback; ma_ptr pStreamCapture;
ma_mutex rerouteLock;
ma_aaudio_usage usage;
ma_aaudio_content_type contentType;
ma_aaudio_input_preset inputPreset;
ma_aaudio_allowed_capture_policy allowedCapturePolicy;
ma_bool32 noAutoStartAfterReroute;
} aaudio;
#endif
#ifdef MA_SUPPORT_OPENSL
struct
{ ma_ptr pOutputMixObj; ma_ptr pOutputMix; ma_ptr pAudioPlayerObj; ma_ptr pAudioPlayer; ma_ptr pAudioRecorderObj; ma_ptr pAudioRecorder; ma_ptr pBufferQueuePlayback; ma_ptr pBufferQueueCapture;
ma_bool32 isDrainingCapture;
ma_bool32 isDrainingPlayback;
M3 currentBufferIndexPlayback;
M3 currentBufferIndexCapture;
ma_uint8*pBufferPlayback;
ma_uint8*pBufferCapture;
} opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
struct
{ int audioContext; int audioWorklet;
float*pIntermediaryBuffer;
Mv*pStackBuffer;
Me initResult;
int deviceIndex;
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_semaphore operationSemaphore;
M3 operation;
Me operationResult;
ma_timer timer;
double priorRunTime;
M3 currentPeriodFramesRemainingPlayback;
M3 currentPeriodFramesRemainingCapture;
M6 lastProcessedFramePlayback;
M6 lastProcessedFrameCapture;
ma_atomic_bool32 isStarted;
} 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
#endif
MA_API ma_context_config ma_context_config_init(Mv);
MA_API Me ma_context_init(const ma_backend backends[],M3 backendCount,const ma_context_config*Mo,ma_context*Mc);
MA_API Me ma_context_uninit(ma_context*Mc);
MA_API size_t ma_context_sizeof(Mv);
MA_API ma_log*ma_context_get_log(ma_context*Mc);
MA_API Me ma_context_enumerate_devices(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData);
MA_API Me ma_context_get_devices(ma_context*Mc,ma_device_info**ppPlaybackDeviceInfos,M3*pPlaybackDeviceCount,ma_device_info**ppCaptureDeviceInfos,M3*pCaptureDeviceCount);
MA_API Me ma_context_get_device_info(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo);
MA_API ma_bool32 ma_context_is_loopback_supported(ma_context*Mc);
MA_API ma_device_config ma_device_config_init(ma_device_type deviceType);
MA_API Me ma_device_init(ma_context*Mc,const ma_device_config*Mo,ma_device*Md);
MA_API Me ma_device_init_ex(const ma_backend backends[],M3 backendCount,const ma_context_config*pContextConfig,const ma_device_config*Mo,ma_device*Md);
MA_API Mv ma_device_uninit(ma_device*Md);
MA_API ma_context*ma_device_get_context(ma_device*Md);
MA_API ma_log*ma_device_get_log(ma_device*Md);
MA_API Me ma_device_get_info(ma_device*Md,ma_device_type type,ma_device_info*pDeviceInfo);
MA_API Me ma_device_get_name(ma_device*Md,ma_device_type type,char*pName,size_t nameCap,size_t*pLengthNotIncludingNullTerminator);
MA_API Me ma_device_start(ma_device*Md);
MA_API Me ma_device_stop(ma_device*Md);
MA_API ma_bool32 ma_device_is_started(const ma_device*Md);
MA_API ma_device_state ma_device_get_state(const ma_device*Md);
MA_API Me ma_device_post_init(ma_device*Md,ma_device_type deviceType,const ma_device_descriptor*pPlaybackDescriptor,const ma_device_descriptor*pCaptureDescriptor);
MA_API Me ma_device_set_master_volume(ma_device*Md,float volume);
MA_API Me ma_device_get_master_volume(ma_device*Md,float*pVolume);
MA_API Me ma_device_set_master_volume_db(ma_device*Md,float gainDB);
MA_API Me ma_device_get_master_volume_db(ma_device*Md,float*pGainDB);
MA_API Me ma_device_handle_backend_data_callback(ma_device*Md,Mv*pOutput,const Mv*pInput,M3 frameCount);
MA_API M3 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor*pDescriptor,M3 nativeSampleRate,ma_performance_profile performanceProfile);
MA_API const char*ma_get_backend_name(ma_backend backend);
MA_API Me ma_get_backend_from_name(const char*pBackendName,ma_backend*pBackend);
MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend);
MA_API Me ma_get_enabled_backends(ma_backend*pBackends,size_t backendCap,size_t*pBackendCount);
MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend);
#endif
MA_API M3 ma_calculate_buffer_size_in_milliseconds_from_frames(M3 bufferSizeInFrames,M3 sampleRate);
MA_API M3 ma_calculate_buffer_size_in_frames_from_milliseconds(M3 bufferSizeInMilliseconds,M3 sampleRate);
MA_API Mv ma_copy_pcm_frames(Mv*dst,const Mv*src,M6 frameCount,ma_format format,M3 Mh);
MA_API Mv ma_silence_pcm_frames(Mv*p,M6 frameCount,ma_format format,M3 Mh);
MA_API Mv*ma_offset_pcm_frames_ptr(Mv*p,M6 offsetInFrames,ma_format format,M3 Mh);
MA_API const Mv*ma_offset_pcm_frames_const_ptr(const Mv*p,M6 offsetInFrames,ma_format format,M3 Mh);
static MA_INLINE float*ma_offset_pcm_frames_ptr_f32(float*p,M6 offsetInFrames,M3 Mh) { Mr (float*)ma_offset_pcm_frames_ptr((Mv*)p,offsetInFrames,ma_format_f32,Mh); }
static MA_INLINE const float*ma_offset_pcm_frames_const_ptr_f32(const float*p,M6 offsetInFrames,M3 Mh) { Mr (const float*)ma_offset_pcm_frames_const_ptr((const Mv*)p,offsetInFrames,ma_format_f32,Mh); }
MA_API Mv ma_clip_samples_u8(ma_uint8*pDst,const ma_int16*pSrc,M6 count);
MA_API Mv ma_clip_samples_s16(ma_int16*pDst,const ma_int32*pSrc,M6 count);
MA_API Mv ma_clip_samples_s24(ma_uint8*pDst,const ma_int64*pSrc,M6 count);
MA_API Mv ma_clip_samples_s32(ma_int32*pDst,const ma_int64*pSrc,M6 count);
MA_API Mv ma_clip_samples_f32(float*pDst,const float*pSrc,M6 count);
MA_API Mv ma_clip_pcm_frames(Mv*pDst,const Mv*pSrc,M6 frameCount,ma_format format,M3 Mh);
MA_API Mv ma_copy_and_apply_volume_factor_u8(ma_uint8*pSamplesOut,const ma_uint8*pSamplesIn,M6 sampleCount,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_s16(ma_int16*pSamplesOut,const ma_int16*pSamplesIn,M6 sampleCount,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_s24(Mv*pSamplesOut,const Mv*pSamplesIn,M6 sampleCount,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_s32(ma_int32*pSamplesOut,const ma_int32*pSamplesIn,M6 sampleCount,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_f32(float*pSamplesOut,const float*pSamplesIn,M6 sampleCount,float factor);
MA_API Mv ma_apply_volume_factor_u8(ma_uint8*pSamples,M6 sampleCount,float factor);
MA_API Mv ma_apply_volume_factor_s16(ma_int16*pSamples,M6 sampleCount,float factor);
MA_API Mv ma_apply_volume_factor_s24(Mv*pSamples,M6 sampleCount,float factor);
MA_API Mv ma_apply_volume_factor_s32(ma_int32*pSamples,M6 sampleCount,float factor);
MA_API Mv ma_apply_volume_factor_f32(float*pSamples,M6 sampleCount,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8*pFramesOut,const ma_uint8*pFramesIn,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16*pFramesOut,const ma_int16*pFramesIn,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_s24(Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32*pFramesOut,const ma_int32*pFramesIn,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_f32(float*pFramesOut,const float*pFramesIn,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames(Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount,ma_format format,M3 Mh,float factor);
MA_API Mv ma_apply_volume_factor_pcm_frames_u8(ma_uint8*pFrames,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_apply_volume_factor_pcm_frames_s16(ma_int16*pFrames,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_apply_volume_factor_pcm_frames_s24(Mv*pFrames,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_apply_volume_factor_pcm_frames_s32(ma_int32*pFrames,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_apply_volume_factor_pcm_frames_f32(float*pFrames,M6 frameCount,M3 Mh,float factor);
MA_API Mv ma_apply_volume_factor_pcm_frames(Mv*pFrames,M6 frameCount,ma_format format,M3 Mh,float factor);
MA_API Mv ma_copy_and_apply_volume_factor_per_channel_f32(float*pFramesOut,const float*pFramesIn,M6 frameCount,M3 Mh,float*pChannelGains);
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8*pDst,const ma_int16*pSrc,M6 count,float volume);
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16*pDst,const ma_int32*pSrc,M6 count,float volume);
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8*pDst,const ma_int64*pSrc,M6 count,float volume);
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32*pDst,const ma_int64*pSrc,M6 count,float volume);
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_f32(float*pDst,const float*pSrc,M6 count,float volume);
MA_API Mv ma_copy_and_apply_volume_and_clip_pcm_frames(Mv*pDst,const Mv*pSrc,M6 frameCount,ma_format format,M3 Mh,float volume);
MA_API float ma_volume_linear_to_db(float factor);
MA_API float ma_volume_db_to_linear(float gain);
MA_API Me ma_mix_pcm_frames_f32(float*pDst,const float*pSrc,M6 frameCount,M3 Mh,float volume);
typedef Mv ma_vfs;
typedef ma_handle ma_vfs_file;
typedef enum
{
MA_OPEN_MODE_READ=0x00000001,MA_OPEN_MODE_WRITE=0x00000002
} ma_open_mode_flags;
typedef enum
{
ma_seek_origin_start,ma_seek_origin_current,ma_seek_origin_end
} ma_seek_origin;
typedef struct
{
M6 sizeInBytes;
} ma_file_info;
typedef struct
{
Me (*onOpen) (ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile);
Me (*onOpenW)(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile);
Me (*onClose)(ma_vfs*pVFS,ma_vfs_file file);
Me (*onRead) (ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead);
Me (*onWrite)(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten);
Me (*onSeek) (ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin);
Me (*onTell) (ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor);
Me (*onInfo) (ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo);
} ma_vfs_callbacks;
MA_API Me ma_vfs_open(ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile);
MA_API Me ma_vfs_open_w(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile);
MA_API Me ma_vfs_close(ma_vfs*pVFS,ma_vfs_file file);
MA_API Me ma_vfs_read(ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead);
MA_API Me ma_vfs_write(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten);
MA_API Me ma_vfs_seek(ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin);
MA_API Me ma_vfs_tell(ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor);
MA_API Me ma_vfs_info(ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo);
MA_API Me ma_vfs_open_and_read_file(ma_vfs*pVFS,const char*pFilePath,Mv**ppData,size_t*pSize,const ma_allocation_callbacks*pAllocationCallbacks);
typedef struct
{
ma_vfs_callbacks cb;
ma_allocation_callbacks allocationCallbacks;
} ma_default_vfs;
MA_API Me ma_default_vfs_init(ma_default_vfs*pVFS,const ma_allocation_callbacks*pAllocationCallbacks);
typedef Me (*ma_read_proc)(Mv*pUserData,Mv*pBufferOut,size_t bytesToRead,size_t*pBytesRead);
typedef Me (*ma_seek_proc)(Mv*pUserData,ma_int64 offset,ma_seek_origin origin);
typedef Me (*ma_tell_proc)(Mv*pUserData,ma_int64*pCursor);
#ifdef __cplusplus
}
#endif
#endif
#if defined(Q_CREATOR_RUN)||defined(__INTELLISENSE__)||defined(__CDT_PARSER__)
#define MINIAUDIO_IMPLEMENTATION
#endif
#if defined(MINIAUDIO_IMPLEMENTATION)||defined(MA_IMPLEMENTATION)
#ifndef miniaudio_c
#define miniaudio_c
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#if !defined(_MSC_VER)&&!defined(__DMC__)
#include <strings.h>
#include <wchar.h>
#endif
#ifdef _MSC_VER
#include <float.h>
#endif
#if defined(MA_WIN32)
#include <windows.h>
#ifndef STGM_READ
#define STGM_READ 0x00000000L
#endif
#ifndef CLSCTX_ALL
#define CLSCTX_ALL 23
#endif
typedef struct ma_IUnknown ma_IUnknown;
#endif
#if !defined(MA_WIN32)
#include <sched.h>
#include <sys/time.h>
#include <pthread.h>
#endif
#ifdef MA_NX
#include <time.h>
#endif
#include <sys/stat.h>
#ifdef MA_EMSCRIPTEN
#include <emscripten/emscripten.h>
#endif
#if !defined(MA_64BIT)&&!defined(MA_32BIT)
#ifdef _WIN32
#ifdef _WIN64
#define MA_64BIT
#else
#define MA_32BIT
#endif
#endif
#endif
#if !defined(MA_64BIT)&&!defined(MA_32BIT)
#ifdef __GNUC__
#ifdef __LP64__
#define MA_64BIT
#else
#define MA_32BIT
#endif
#endif
#endif
#if !defined(MA_64BIT)&&!defined(MA_32BIT)
#include <stdint.h>
#if INTPTR_MAX==INT64_MAX
#define MA_64BIT
#else
#define MA_32BIT
#endif
#endif
#if defined(__arm__)||defined(_M_ARM)
#define MA_ARM32
#endif
#if defined(__arm64)||defined(__arm64__)||defined(__aarch64__)||defined(_M_ARM64)
#define MA_ARM64
#endif
#if defined(__x86_64__)||defined(_M_X64)
#define MA_X64
#elif defined(__i386)||defined(_M_IX86)
#define MA_X86
#elif defined(MA_ARM32)||defined(MA_ARM64)
#define MA_ARM
#endif
#if (defined(MA_X64)||defined(MA_X86))&&!defined(__COSMOPOLITAN__)
#if defined(_MSC_VER)&&!defined(__clang__)
#if _MSC_VER>=1400&&!defined(MA_NO_SSE2)
#define MA_SUPPORT_SSE2
#endif
#if _MSC_VER>=1700&&!defined(MA_NO_AVX2)
#define MA_SUPPORT_AVX2
#endif
#else
#if defined(__SSE2__)&&!defined(MA_NO_SSE2)
#define MA_SUPPORT_SSE2
#endif
#if defined(__AVX2__)&&!defined(MA_NO_AVX2)
#define MA_SUPPORT_AVX2
#endif
#endif
#if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
#if !defined(MA_SUPPORT_SSE2) && !defined(MA_NO_SSE2) && __has_include(<emmintrin.h>)
#define MA_SUPPORT_SSE2
#endif
#if !defined(MA_SUPPORT_AVX2) && !defined(MA_NO_AVX2) && __has_include(<immintrin.h>)
#define MA_SUPPORT_AVX2
#endif
#endif
#if defined(MA_SUPPORT_AVX2)||defined(MA_SUPPORT_AVX)
#include <immintrin.h>
#elif defined(MA_SUPPORT_SSE2)
#include <emmintrin.h>
#endif
#endif
#if defined(MA_ARM)
#if !defined(MA_NO_NEON)&&(defined(__ARM_NEON)||defined(__aarch64__)||defined(_M_ARM64))
#define MA_SUPPORT_NEON
#include <arm_neon.h>
#endif
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4752)
#pragma warning(disable:4049)
#endif
#if defined(MA_X64)||defined(MA_X86)
#if defined(_MSC_VER)&&!defined(__clang__)
#if _MSC_VER>=1400
#include <intrin.h>
static MA_INLINE Mv ma_cpuid(int info[4],int fid)
{
__cpuid(info,fid);
}
#else
#define MA_NO_CPUID
#endif
#if _MSC_VER>=1600&&(defined(_MSC_FULL_VER)&&_MSC_FULL_VER>=160040219)
static MA_INLINE unsigned __int64 ma_xgetbv(int reg)
{
Mr _xgetbv(reg);
}
#else
#define MA_NO_XGETBV
#endif
#elif (defined(__GNUC__)||defined(__clang__))&&!defined(MA_ANDROID)
static MA_INLINE Mv ma_cpuid(int info[4],int fid)
{
#if defined(MA_X86)&&defined(__PIC__)
__asm__ __volatile__ (
 "xchg{l} {%%}ebx, %k1;"
 "cpuid;"
 "xchg{l} {%%}ebx, %k1;"
 : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
);
#else
__asm__ __volatile__ (
 "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
);
#endif
}
static MA_INLINE M6 ma_xgetbv(int reg)
{
unsigned int hi;
unsigned int lo;
__asm__ __volatile__ (
"xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg)
);
Mr ((M6)hi<<32)|(M6)lo;
}
#else
#define MA_NO_CPUID
#define MA_NO_XGETBV
#endif
#else
#define MA_NO_CPUID
#define MA_NO_XGETBV
#endif
static MA_INLINE ma_bool32 ma_has_sse2(Mv)
{
#if defined(MA_SUPPORT_SSE2)
#if (defined(MA_X64)||defined(MA_X86))&&!defined(MA_NO_SSE2)
#if defined(MA_X64)
Mr MA_TRUE;
#elif (defined(_M_IX86_FP)&&_M_IX86_FP==2)||defined(__SSE2__)
Mr MA_TRUE;
#else
#if defined(MA_NO_CPUID)
Mr MA_FALSE;
#else
int info[4];
ma_cpuid(info,1);
Mr (info[3]&(1<<26)) !=0;
#endif
#endif
#else
Mr MA_FALSE;
#endif
#else
Mr MA_FALSE;
#endif
}
#if 0
static MA_INLINE ma_bool32 ma_has_avx()
{
#if defined(MA_SUPPORT_AVX)
#if (defined(MA_X64)||defined(MA_X86))&&!defined(MA_NO_AVX)
#if defined(_AVX_)||defined(__AVX__)
Mr MA_TRUE;
#else
#if defined(MA_NO_CPUID)||defined(MA_NO_XGETBV)
Mr MA_FALSE;
#else
int info[4];
ma_cpuid(info,1);
if (((info[2]&(1<<27)) !=0)&&((info[2]&(1<<28)) !=0)) {
 M6 xrc=ma_xgetbv(0);
 if ((xrc&0x06)==0x06) {
 Mr MA_TRUE;
 } else {
 Mr MA_FALSE;
 }
} else {
 Mr MA_FALSE;
}
#endif
#endif
#else
Mr MA_FALSE;
#endif
#else
Mr MA_FALSE;
#endif
}
#endif
static MA_INLINE ma_bool32 ma_has_avx2(Mv)
{
#if defined(MA_SUPPORT_AVX2)
#if (defined(MA_X64)||defined(MA_X86))&&!defined(MA_NO_AVX2)
#if defined(_AVX2_)||defined(__AVX2__)
Mr MA_TRUE;
#else
#if defined(MA_NO_CPUID)||defined(MA_NO_XGETBV)
Mr MA_FALSE;
#else
int info1[4];
int info7[4];
ma_cpuid(info1,1);
ma_cpuid(info7,7);
if (((info1[2]&(1<<27)) !=0)&&((info7[1]&(1<<5)) !=0)) {
 M6 xrc=ma_xgetbv(0);
 if ((xrc&0x06)==0x06) {
 Mr MA_TRUE;
 } else {
 Mr MA_FALSE;
 }
} else {
 Mr MA_FALSE;
}
#endif
#endif
#else
Mr MA_FALSE;
#endif
#else
Mr MA_FALSE;
#endif
}
static MA_INLINE ma_bool32 ma_has_neon(Mv)
{
#if defined(MA_SUPPORT_NEON)
#if defined(MA_ARM)&&!defined(MA_NO_NEON)
#if (defined(__ARM_NEON)||defined(__aarch64__)||defined(_M_ARM64))
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
#else
Mr MA_FALSE;
#endif
#else
Mr MA_FALSE;
#endif
}
#if defined(__has_builtin)
#define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x)
#else
#define MA_COMPILER_HAS_BUILTIN(x) 0
#endif
#ifndef MA_ASSUME
#if MA_COMPILER_HAS_BUILTIN(__builtin_assume)
#define MA_ASSUME(x) __builtin_assume(x)
#elif MA_COMPILER_HAS_BUILTIN(__builtin_unreachable)
#define MA_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(_MSC_VER)
#define MA_ASSUME(x) __assume(x)
#else
#define MA_ASSUME(x) (Mv)(x)
#endif
#endif
#ifndef MA_RESTRICT
#if defined(__clang__)||defined(__GNUC__)||defined(_MSC_VER)
#define MA_RESTRICT __restrict
#else
#define MA_RESTRICT
#endif
#endif
#if defined(_MSC_VER)&&_MSC_VER>=1400
#define MA_HAS_BYTESWAP16_INTRINSIC
#define MA_HAS_BYTESWAP32_INTRINSIC
#define MA_HAS_BYTESWAP64_INTRINSIC
#elif defined(__clang__)
#if MA_COMPILER_HAS_BUILTIN(__builtin_bswap16)
#define MA_HAS_BYTESWAP16_INTRINSIC
#endif
#if MA_COMPILER_HAS_BUILTIN(__builtin_bswap32)
#define MA_HAS_BYTESWAP32_INTRINSIC
#endif
#if MA_COMPILER_HAS_BUILTIN(__builtin_bswap64)
#define MA_HAS_BYTESWAP64_INTRINSIC
#endif
#elif defined(__GNUC__)
#if ((__GNUC__>4)||(__GNUC__==4&&__GNUC_MINOR__>=3))
#define MA_HAS_BYTESWAP32_INTRINSIC
#define MA_HAS_BYTESWAP64_INTRINSIC
#endif
#if ((__GNUC__>4)||(__GNUC__==4&&__GNUC_MINOR__>=8))
#define MA_HAS_BYTESWAP16_INTRINSIC
#endif
#endif
static MA_INLINE ma_bool32 ma_is_little_endian(Mv)
{
#if defined(MA_X86)||defined(MA_X64)
Mr MA_TRUE;
#else
int n=1;
Mr (*(char*)&n)==1;
#endif
}
static MA_INLINE ma_bool32 ma_is_big_endian(Mv)
{
Mr !ma_is_little_endian();
}
static MA_INLINE M3 ma_swap_endian_uint32(M3 n)
{
#ifdef MA_HAS_BYTESWAP32_INTRINSIC
#if defined(_MSC_VER)
Mr _byteswap_ulong(n);
#elif defined(__GNUC__)||defined(__clang__)
#if defined(MA_ARM)&&(defined(__ARM_ARCH)&&__ARM_ARCH>=6)&&!defined(MA_64BIT)
M3 r;
__asm__ __volatile__ (
#if defined(MA_64BIT)
"rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)
#else
"rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
#endif
);
Mr r;
#else
Mr __builtin_bswap32(n);
#endif
#else
#error "This compiler does not support the byte swap intrinsic."
#endif
#else
Mr ((n&0xFF000000)>>24)|
((n&0x00FF0000)>>8)|
((n&0x0000FF00)<<8)|
((n&0x000000FF)<<24);
#endif
}
#if !defined(MA_EMSCRIPTEN)
#ifdef MA_WIN32
static Mv ma_sleep__win32(M3 milliseconds)
{
Sleep((DWORD)milliseconds);
}
#endif
#ifdef MA_POSIX
static Mv ma_sleep__posix(M3 milliseconds)
{
#ifdef MA_EMSCRIPTEN
(Mv)milliseconds;
MA_ASSERT(MA_FALSE);
#else
#if (defined(_POSIX_C_SOURCE)&&_POSIX_C_SOURCE>=199309L)||defined(MA_NX)
struct timespec ts;
ts.tv_sec=milliseconds / 1000;
ts.tv_nsec=milliseconds % 1000*1000000;
nanosleep(&ts,NULL);
#else
struct timeval tv;
tv.tv_sec=milliseconds / 1000;
tv.tv_usec=milliseconds % 1000*1000;
select(0,NULL,NULL,NULL,&tv);
#endif
#endif
}
#endif
static MA_INLINE Mv ma_sleep(M3 milliseconds)
{
#ifdef MA_WIN32
ma_sleep__win32(milliseconds);
#endif
#ifdef MA_POSIX
ma_sleep__posix(milliseconds);
#endif
}
#endif
static MA_INLINE Mv ma_yield(Mv)
{
#if defined(__i386)||defined(_M_IX86)||defined(__x86_64__)||defined(_M_X64)
#if (defined(_MSC_VER)||defined(__WATCOMC__)||defined(__DMC__))&&!defined(__clang__)
#if _MSC_VER>=1400
_mm_pause();
#else
#if defined(__DMC__)
__asm nop;
#else
__asm pause;
#endif
#endif
#else
__asm__ __volatile__ ("pause");
#endif
#elif (defined(__arm__)&&defined(__ARM_ARCH)&&__ARM_ARCH>=7)||defined(_M_ARM64)||(defined(_M_ARM)&&_M_ARM>=7)||defined(__ARM_ARCH_6K__)||defined(__ARM_ARCH_6T2__)
#if defined(_MSC_VER)
__yield();
#else
__asm__ __volatile__ ("yield");
#endif
#else
#endif
}
#define MA_MM_DENORMALS_ZERO_MASK 0x0040
#define MA_MM_FLUSH_ZERO_MASK 0x8000
static MA_INLINE unsigned int ma_disable_denormals(Mv)
{
unsigned int prevState;
#if defined(_MSC_VER)
{
#if _MSC_VER<=1200
{
prevState=_statusfp();
_controlfp(prevState|_DN_FLUSH,_MCW_DN);
}
#else
{
unsigned int unused;
_controlfp_s(&prevState,0,0);
_controlfp_s(&unused,prevState|_DN_FLUSH,_MCW_DN);
}
#endif
}
#elif defined(MA_X86)||defined(MA_X64)
{
#if defined(__SSE2__)&&!(defined(__TINYC__)||defined(__WATCOMC__)||defined(__COSMOPOLITAN__))
{
prevState=_mm_getcsr();
_mm_setcsr(prevState|MA_MM_DENORMALS_ZERO_MASK|MA_MM_FLUSH_ZERO_MASK);
}
#else
{
prevState=0;
}
#endif
}
#else
{
prevState=0;
}
#endif
Mr prevState;
}
static MA_INLINE Mv ma_restore_denormals(unsigned int prevState)
{
#if defined(_MSC_VER)
{
#if _MSC_VER<=1200
{
_controlfp(prevState,_MCW_DN);
}
#else
{
unsigned int unused;
_controlfp_s(&unused,prevState,_MCW_DN);
}
#endif
}
#elif defined(MA_X86)||defined(MA_X64)
{
#if defined(__SSE2__)&&!(defined(__TINYC__)||defined(__WATCOMC__)||defined(__COSMOPOLITAN__))
{
_mm_setcsr(prevState);
}
#else
{
(Mv)prevState;
}
#endif
}
#else
{
(Mv)prevState;
}
#endif
}
#ifdef MA_ANDROID
#include <sys/system_properties.h>
int ma_android_sdk_version()
{
char sdkVersion[PROP_VALUE_MAX+1]={0,};
if (__system_property_get("ro.build.version.sdk", sdkVersion)) {
Mr atoi(sdkVersion);
}
Mr 0;
}
#endif
#ifndef MA_COINIT_VALUE
#define MA_COINIT_VALUE 0
#endif
#ifndef MA_FLT_MAX
#ifdef FLT_MAX
#define MA_FLT_MAX FLT_MAX
#else
#define MA_FLT_MAX 3.402823466e+38F
#endif
#endif
#ifndef MA_PI
#define MA_PI 3.14159265358979323846264f
#endif
#ifndef MA_PI_D
#define MA_PI_D 3.14159265358979323846264
#endif
#ifndef MA_TAU
#define MA_TAU 6.28318530717958647693f
#endif
#ifndef MA_TAU_D
#define MA_TAU_D 6.28318530717958647693
#endif
#ifndef MA_DEFAULT_FORMAT
#define MA_DEFAULT_FORMAT ma_format_f32
#endif
#ifndef MA_DEFAULT_CHANNELS
#define MA_DEFAULT_CHANNELS 2
#endif
#ifndef MA_DEFAULT_SAMPLE_RATE
#define MA_DEFAULT_SAMPLE_RATE 48000
#endif
#ifndef MA_DEFAULT_PERIODS
#define MA_DEFAULT_PERIODS 3
#endif
#ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY
#define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY 10
#endif
#ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE
#define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE 100
#endif
#ifndef MA_DEFAULT_RESAMPLER_LPF_ORDER
#if MA_MAX_FILTER_ORDER>=4
#define MA_DEFAULT_RESAMPLER_LPF_ORDER 4
#else
#define MA_DEFAULT_RESAMPLER_LPF_ORDER MA_MAX_FILTER_ORDER
#endif
#endif
#if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
static M3 g_maStandardSampleRatePriorities[]={
(M3)ma_standard_sample_rate_48000,(M3)ma_standard_sample_rate_44100,(M3)ma_standard_sample_rate_32000,(M3)ma_standard_sample_rate_24000,(M3)ma_standard_sample_rate_22050,(M3)ma_standard_sample_rate_88200,(M3)ma_standard_sample_rate_96000,(M3)ma_standard_sample_rate_176400,(M3)ma_standard_sample_rate_192000,(M3)ma_standard_sample_rate_16000,(M3)ma_standard_sample_rate_11025,(M3)ma_standard_sample_rate_8000,(M3)ma_standard_sample_rate_352800,(M3)ma_standard_sample_rate_384000
};
static MA_INLINE ma_bool32 ma_is_standard_sample_rate(M3 sampleRate)
{
M3 iSampleRate;
for (iSampleRate=0; iSampleRate<sizeof(g_maStandardSampleRatePriorities) / sizeof(g_maStandardSampleRatePriorities[0]); iSampleRate+=1) {
if (g_maStandardSampleRatePriorities[iSampleRate]==sampleRate) {
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
static ma_format g_maFormatPriorities[]={
ma_format_s16,ma_format_f32,ma_format_s32,ma_format_s24,ma_format_u8
};
#if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=6)))
#pragma GCC diagnostic pop
#endif
MA_API Mv ma_version(M3*pMajor,M3*pMinor,M3*pRevision)
{
if (pMajor) {
*pMajor=MA_VERSION_MAJOR;
}
if (pMinor) {
*pMinor=MA_VERSION_MINOR;
}
if (pRevision) {
*pRevision=MA_VERSION_REVISION;
}
}
MA_API const char*ma_version_string(Mv)
{
Mr MA_VERSION_STRING;
}
#ifndef MA_ASSERT
#define MA_ASSERT(condition) assert(condition)
#endif
#ifndef MA_MALLOC
#define MA_MALLOC(sz) malloc((sz))
#endif
#ifndef MA_REALLOC
#define MA_REALLOC(p,sz) realloc((p),(sz))
#endif
#ifndef MA_FREE
#define MA_FREE(p) free((p))
#endif
static MA_INLINE Mv ma_zero_memory_default(Mv*p,size_t sz)
{
if (p==NULL) {
MA_ASSERT(sz==0);
Mr;
}
if (sz>0) {
memset(p,0,sz);
}
}
#ifndef MA_ZERO_MEMORY
#define MA_ZERO_MEMORY(p,sz) ma_zero_memory_default((p),(sz))
#endif
#ifndef MA_COPY_MEMORY
#define MA_COPY_MEMORY(dst,src,sz) memcpy((dst),(src),(sz))
#endif
#ifndef MA_MOVE_MEMORY
#define MA_MOVE_MEMORY(dst,src,sz) memmove((dst),(src),(sz))
#endif
#define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p),sizeof(*(p)))
#define ma_countof(x) (sizeof(x) / sizeof(x[0]))
#define ma_max(x,y) (((x)>(y))?(x):(y))
#define ma_min(x,y) (((x)<(y))?(x):(y))
#define ma_abs(x) (((x)>0)?(x):-(x))
#define ma_clamp(x,lo,hi) (ma_max(lo,ma_min(x,hi)))
#define ma_offset_ptr(p,offset) (((ma_uint8*)(p))+(offset))
#define ma_align(x,a) (((x)+((a)-1))&~((a)-1))
#define ma_align_64(x) ma_align(x,8)
#define ma_buffer_frame_capacity(buffer,Mh,format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (Mh))
static MA_INLINE double ma_sind(double x)
{
Mr sin(x);
}
static MA_INLINE double ma_expd(double x)
{
Mr exp(x);
}
static MA_INLINE double ma_logd(double x)
{
Mr log(x);
}
static MA_INLINE double ma_powd(double x,double y)
{
Mr pow(x,y);
}
static MA_INLINE double ma_sqrtd(double x)
{
Mr sqrt(x);
}
static MA_INLINE float ma_rsqrtf(float x)
{
#if defined(MA_SUPPORT_SSE2)&&!defined(MA_NO_SSE2)&&(defined(MA_X64)||(defined(_M_IX86_FP)&&_M_IX86_FP==2)||defined(__SSE2__))
{
#if defined(__GNUC__)||defined(__clang__)
{
float Mf;
__asm__ __volatile__("rsqrtss %1, %0" : "=x"(Mf) : "x"(x));
Mr Mf;
}
#else
{
Mr _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ps1(x)));
}
#endif
}
#else
{
Mr 1 / (float)ma_sqrtd(x);
}
#endif
}
static MA_INLINE float ma_sinf(float x)
{
Mr (float)ma_sind((float)x);
}
static MA_INLINE double ma_cosd(double x)
{
Mr ma_sind((MA_PI_D*0.5)-x);
}
static MA_INLINE float ma_cosf(float x)
{
Mr (float)ma_cosd((float)x);
}
static MA_INLINE double ma_log10d(double x)
{
Mr ma_logd(x)*0.43429448190325182765;
}
static MA_INLINE float ma_powf(float x,float y)
{
Mr (float)ma_powd((double)x,(double)y);
}
static MA_INLINE float ma_log10f(float x)
{
Mr (float)ma_log10d((double)x);
}
static MA_INLINE double ma_degrees_to_radians(double degrees)
{
Mr degrees*0.01745329252;
}
static MA_INLINE double ma_radians_to_degrees(double radians)
{
Mr radians*57.295779512896;
}
static MA_INLINE float ma_degrees_to_radians_f(float degrees)
{
Mr degrees*0.01745329252f;
}
static MA_INLINE float ma_radians_to_degrees_f(float radians)
{
Mr radians*57.295779512896f;
}
MA_API MA_NO_INLINE int ma_strcpy_s(char*dst,size_t dstSizeInBytes,const char*src)
{
size_t i;
if (dst==0) {
Mr 22;
}
if (dstSizeInBytes==0) {
Mr 34;
}
if (src==0) {
dst[0]='\0';
Mr 22;
}
for (i=0; i<dstSizeInBytes&&src[i] !='\0';++i) {
dst[i]=src[i];
}
if (i<dstSizeInBytes) {
dst[i]='\0';
Mr 0;
}
dst[0]='\0';
Mr 34;
}
MA_API MA_NO_INLINE int ma_wcscpy_s(wchar_t*dst,size_t dstCap,const wchar_t*src)
{
size_t i;
if (dst==0) {
Mr 22;
}
if (dstCap==0) {
Mr 34;
}
if (src==0) {
dst[0]='\0';
Mr 22;
}
for (i=0; i<dstCap&&src[i] !='\0';++i) {
dst[i]=src[i];
}
if (i<dstCap) {
dst[i]='\0';
Mr 0;
}
dst[0]='\0';
Mr 34;
}
MA_API MA_NO_INLINE int ma_strncpy_s(char*dst,size_t dstSizeInBytes,const char*src,size_t count)
{
size_t maxcount;
size_t i;
if (dst==0) {
Mr 22;
}
if (dstSizeInBytes==0) {
Mr 34;
}
if (src==0) {
dst[0]='\0';
Mr 22;
}
maxcount=count;
if (count==((size_t)-1)||count>=dstSizeInBytes) {
maxcount=dstSizeInBytes-1;
}
for (i=0; i<maxcount&&src[i] !='\0';++i) {
dst[i]=src[i];
}
if (src[i]=='\0'||i==count||count==((size_t)-1)) {
dst[i]='\0';
Mr 0;
}
dst[0]='\0';
Mr 34;
}
MA_API MA_NO_INLINE int ma_strcat_s(char*dst,size_t dstSizeInBytes,const char*src)
{
char*dstorig;
if (dst==0) {
Mr 22;
}
if (dstSizeInBytes==0) {
Mr 34;
}
if (src==0) {
dst[0]='\0';
Mr 22;
}
dstorig=dst;
while (dstSizeInBytes>0&&dst[0] !='\0') {
dst+=1;
dstSizeInBytes-=1;
}
if (dstSizeInBytes==0) {
Mr 22;
}
while (dstSizeInBytes>0&&src[0] !='\0') {
*dst++=*src++;
dstSizeInBytes-=1;
}
if (dstSizeInBytes>0) {
dst[0]='\0';
} else {
dstorig[0]='\0';
Mr 34;
}
Mr 0;
}
MA_API MA_NO_INLINE int ma_strncat_s(char*dst,size_t dstSizeInBytes,const char*src,size_t count)
{
char*dstorig;
if (dst==0) {
Mr 22;
}
if (dstSizeInBytes==0) {
Mr 34;
}
if (src==0) {
Mr 22;
}
dstorig=dst;
while (dstSizeInBytes>0&&dst[0] !='\0') {
dst+=1;
dstSizeInBytes-=1;
}
if (dstSizeInBytes==0) {
Mr 22;
}
if (count==((size_t)-1)) {
count=dstSizeInBytes-1;
}
while (dstSizeInBytes>0&&src[0] !='\0'&&count>0) {
*dst++=*src++;
dstSizeInBytes-=1;
count-=1;
}
if (dstSizeInBytes>0) {
dst[0]='\0';
} else {
dstorig[0]='\0';
Mr 34;
}
Mr 0;
}
MA_API MA_NO_INLINE int ma_itoa_s(int value,char*dst,size_t dstSizeInBytes,int radix)
{
int sign;
unsigned int valueU;
char*dstEnd;
if (dst==NULL||dstSizeInBytes==0) {
Mr 22;
}
if (radix<2||radix>36) {
dst[0]='\0';
Mr 22;
}
sign=(value<0&&radix==10)?-1:1;
if (value<0) {
valueU=-value;
} else {
valueU=value;
}
dstEnd=dst;
do
{
int remainder=valueU % radix;
if (remainder>9) {
*dstEnd=(char)((remainder-10)+'a');
} else {
*dstEnd=(char)(remainder+'0');
}
dstEnd+=1;
dstSizeInBytes-=1;
valueU /=radix;
} while (dstSizeInBytes>0&&valueU>0);
if (dstSizeInBytes==0) {
dst[0]='\0';
Mr 22;
}
if (sign<0) {
*dstEnd++='-';
dstSizeInBytes-=1;
}
if (dstSizeInBytes==0) {
dst[0]='\0';
Mr 22;
}
*dstEnd='\0';
dstEnd-=1;
while (dst<dstEnd) {
char temp=*dst;
*dst=*dstEnd;
*dstEnd=temp;
dst+=1;
dstEnd-=1;
}
Mr 0;
}
MA_API MA_NO_INLINE int ma_strcmp(const char*str1,const char*str2)
{
if (str1==str2) Mr 0;
if (str1==NULL) Mr-1;
if (str2==NULL) Mr 1;
for (;;) {
if (str1[0]=='\0') {
break;
}
if (str1[0] !=str2[0]) {
break;
}
str1+=1;
str2+=1;
}
Mr ((unsigned char*)str1)[0]-((unsigned char*)str2)[0];
}
MA_API MA_NO_INLINE int ma_strappend(char*dst,size_t dstSize,const char*srcA,const char*srcB)
{
int Mf;
Mf=ma_strncpy_s(dst,dstSize,srcA,(size_t)-1);
if (Mf !=0) {
Mr Mf;
}
Mf=ma_strncat_s(dst,dstSize,srcB,(size_t)-1);
if (Mf !=0) {
Mr Mf;
}
Mr Mf;
}
MA_API MA_NO_INLINE char*ma_copy_string(const char*src,const ma_allocation_callbacks*pAllocationCallbacks)
{
size_t sz;
char*dst;
if (src==NULL) {
Mr NULL;
}
sz=strlen(src)+1;
dst=(char*)ma_malloc(sz,pAllocationCallbacks);
if (dst==NULL) {
Mr NULL;
}
ma_strcpy_s(dst,sz,src);
Mr dst;
}
MA_API MA_NO_INLINE wchar_t*ma_copy_string_w(const wchar_t*src,const ma_allocation_callbacks*pAllocationCallbacks)
{
size_t sz=wcslen(src)+1;
wchar_t*dst=(wchar_t*)ma_malloc(sz*sizeof(*dst),pAllocationCallbacks);
if (dst==NULL) {
Mr NULL;
}
ma_wcscpy_s(dst,sz,src);
Mr dst;
}
#include <errno.h>
static Me ma_result_from_errno(int e)
{
if (e==0) {
Mr Ms;
}
#ifdef EPERM
else if (e==EPERM) { Mr MA_INVALID_OPERATION; }
#endif
#ifdef ENOENT
else if (e==ENOENT) { Mr MA_DOES_NOT_EXIST; }
#endif
#ifdef ESRCH
else if (e==ESRCH) { Mr MA_DOES_NOT_EXIST; }
#endif
#ifdef EINTR
else if (e==EINTR) { Mr MA_INTERRUPT; }
#endif
#ifdef EIO
else if (e==EIO) { Mr MA_IO_ERROR; }
#endif
#ifdef ENXIO
else if (e==ENXIO) { Mr MA_DOES_NOT_EXIST; }
#endif
#ifdef E2BIG
else if (e==E2BIG) { Mr MA_INVALID_ARGS; }
#endif
#ifdef ENOEXEC
else if (e==ENOEXEC) { Mr MA_INVALID_FILE; }
#endif
#ifdef EBADF
else if (e==EBADF) { Mr MA_INVALID_FILE; }
#endif
#ifdef ECHILD
else if (e==ECHILD) { Mr MA_ERROR; }
#endif
#ifdef EAGAIN
else if (e==EAGAIN) { Mr MA_UNAVAILABLE; }
#endif
#ifdef ENOMEM
else if (e==ENOMEM) { Mr MA_OUT_OF_MEMORY; }
#endif
#ifdef EACCES
else if (e==EACCES) { Mr MA_ACCESS_DENIED; }
#endif
#ifdef EFAULT
else if (e==EFAULT) { Mr MA_BAD_ADDRESS; }
#endif
#ifdef ENOTBLK
else if (e==ENOTBLK) { Mr MA_ERROR; }
#endif
#ifdef EBUSY
else if (e==EBUSY) { Mr MA_BUSY; }
#endif
#ifdef EEXIST
else if (e==EEXIST) { Mr MA_ALREADY_EXISTS; }
#endif
#ifdef EXDEV
else if (e==EXDEV) { Mr MA_ERROR; }
#endif
#ifdef ENODEV
else if (e==ENODEV) { Mr MA_DOES_NOT_EXIST; }
#endif
#ifdef ENOTDIR
else if (e==ENOTDIR) { Mr MA_NOT_DIRECTORY; }
#endif
#ifdef EISDIR
else if (e==EISDIR) { Mr MA_IS_DIRECTORY; }
#endif
#ifdef EINVAL
else if (e==EINVAL) { Mr MA_INVALID_ARGS; }
#endif
#ifdef ENFILE
else if (e==ENFILE) { Mr MA_TOO_MANY_OPEN_FILES; }
#endif
#ifdef EMFILE
else if (e==EMFILE) { Mr MA_TOO_MANY_OPEN_FILES; }
#endif
#ifdef ENOTTY
else if (e==ENOTTY) { Mr MA_INVALID_OPERATION; }
#endif
#ifdef ETXTBSY
else if (e==ETXTBSY) { Mr MA_BUSY; }
#endif
#ifdef EFBIG
else if (e==EFBIG) { Mr MA_TOO_BIG; }
#endif
#ifdef ENOSPC
else if (e==ENOSPC) { Mr MA_NO_SPACE; }
#endif
#ifdef ESPIPE
else if (e==ESPIPE) { Mr MA_BAD_SEEK; }
#endif
#ifdef EROFS
else if (e==EROFS) { Mr MA_ACCESS_DENIED; }
#endif
#ifdef EMLINK
else if (e==EMLINK) { Mr MA_TOO_MANY_LINKS; }
#endif
#ifdef EPIPE
else if (e==EPIPE) { Mr MA_BAD_PIPE; }
#endif
#ifdef EDOM
else if (e==EDOM) { Mr MA_OUT_OF_RANGE; }
#endif
#ifdef ERANGE
else if (e==ERANGE) { Mr MA_OUT_OF_RANGE; }
#endif
#ifdef EDEADLK
else if (e==EDEADLK) { Mr MA_DEADLOCK; }
#endif
#ifdef ENAMETOOLONG
else if (e==ENAMETOOLONG) { Mr MA_PATH_TOO_LONG; }
#endif
#ifdef ENOLCK
else if (e==ENOLCK) { Mr MA_ERROR; }
#endif
#ifdef ENOSYS
else if (e==ENOSYS) { Mr MA_NOT_IMPLEMENTED; }
#endif
#ifdef ENOTEMPTY
else if (e==ENOTEMPTY) { Mr MA_DIRECTORY_NOT_EMPTY; }
#endif
#ifdef ELOOP
else if (e==ELOOP) { Mr MA_TOO_MANY_LINKS; }
#endif
#ifdef ENOMSG
else if (e==ENOMSG) { Mr MA_NO_MESSAGE; }
#endif
#ifdef EIDRM
else if (e==EIDRM) { Mr MA_ERROR; }
#endif
#ifdef ECHRNG
else if (e==ECHRNG) { Mr MA_ERROR; }
#endif
#ifdef EL2NSYNC
else if (e==EL2NSYNC) { Mr MA_ERROR; }
#endif
#ifdef EL3HLT
else if (e==EL3HLT) { Mr MA_ERROR; }
#endif
#ifdef EL3RST
else if (e==EL3RST) { Mr MA_ERROR; }
#endif
#ifdef ELNRNG
else if (e==ELNRNG) { Mr MA_OUT_OF_RANGE; }
#endif
#ifdef EUNATCH
else if (e==EUNATCH) { Mr MA_ERROR; }
#endif
#ifdef ENOCSI
else if (e==ENOCSI) { Mr MA_ERROR; }
#endif
#ifdef EL2HLT
else if (e==EL2HLT) { Mr MA_ERROR; }
#endif
#ifdef EBADE
else if (e==EBADE) { Mr MA_ERROR; }
#endif
#ifdef EBADR
else if (e==EBADR) { Mr MA_ERROR; }
#endif
#ifdef EXFULL
else if (e==EXFULL) { Mr MA_ERROR; }
#endif
#ifdef ENOANO
else if (e==ENOANO) { Mr MA_ERROR; }
#endif
#ifdef EBADRQC
else if (e==EBADRQC) { Mr MA_ERROR; }
#endif
#ifdef EBADSLT
else if (e==EBADSLT) { Mr MA_ERROR; }
#endif
#ifdef EBFONT
else if (e==EBFONT) { Mr MA_INVALID_FILE; }
#endif
#ifdef ENOSTR
else if (e==ENOSTR) { Mr MA_ERROR; }
#endif
#ifdef ENODATA
else if (e==ENODATA) { Mr MA_NO_DATA_AVAILABLE; }
#endif
#ifdef ETIME
else if (e==ETIME) { Mr MA_TIMEOUT; }
#endif
#ifdef ENOSR
else if (e==ENOSR) { Mr MA_NO_DATA_AVAILABLE; }
#endif
#ifdef ENONET
else if (e==ENONET) { Mr MA_NO_NETWORK; }
#endif
#ifdef ENOPKG
else if (e==ENOPKG) { Mr MA_ERROR; }
#endif
#ifdef EREMOTE
else if (e==EREMOTE) { Mr MA_ERROR; }
#endif
#ifdef ENOLINK
else if (e==ENOLINK) { Mr MA_ERROR; }
#endif
#ifdef EADV
else if (e==EADV) { Mr MA_ERROR; }
#endif
#ifdef ESRMNT
else if (e==ESRMNT) { Mr MA_ERROR; }
#endif
#ifdef ECOMM
else if (e==ECOMM) { Mr MA_ERROR; }
#endif
#ifdef EPROTO
else if (e==EPROTO) { Mr MA_ERROR; }
#endif
#ifdef EMULTIHOP
else if (e==EMULTIHOP) { Mr MA_ERROR; }
#endif
#ifdef EDOTDOT
else if (e==EDOTDOT) { Mr MA_ERROR; }
#endif
#ifdef EBADMSG
else if (e==EBADMSG) { Mr MA_BAD_MESSAGE; }
#endif
#ifdef EOVERFLOW
else if (e==EOVERFLOW) { Mr MA_TOO_BIG; }
#endif
#ifdef ENOTUNIQ
else if (e==ENOTUNIQ) { Mr MA_NOT_UNIQUE; }
#endif
#ifdef EBADFD
else if (e==EBADFD) { Mr MA_ERROR; }
#endif
#ifdef EREMCHG
else if (e==EREMCHG) { Mr MA_ERROR; }
#endif
#ifdef ELIBACC
else if (e==ELIBACC) { Mr MA_ACCESS_DENIED; }
#endif
#ifdef ELIBBAD
else if (e==ELIBBAD) { Mr MA_INVALID_FILE; }
#endif
#ifdef ELIBSCN
else if (e==ELIBSCN) { Mr MA_INVALID_FILE; }
#endif
#ifdef ELIBMAX
else if (e==ELIBMAX) { Mr MA_ERROR; }
#endif
#ifdef ELIBEXEC
else if (e==ELIBEXEC) { Mr MA_ERROR; }
#endif
#ifdef EILSEQ
else if (e==EILSEQ) { Mr MA_INVALID_DATA; }
#endif
#ifdef ERESTART
else if (e==ERESTART) { Mr MA_ERROR; }
#endif
#ifdef ESTRPIPE
else if (e==ESTRPIPE) { Mr MA_ERROR; }
#endif
#ifdef EUSERS
else if (e==EUSERS) { Mr MA_ERROR; }
#endif
#ifdef ENOTSOCK
else if (e==ENOTSOCK) { Mr MA_NOT_SOCKET; }
#endif
#ifdef EDESTADDRREQ
else if (e==EDESTADDRREQ) { Mr MA_NO_ADDRESS; }
#endif
#ifdef EMSGSIZE
else if (e==EMSGSIZE) { Mr MA_TOO_BIG; }
#endif
#ifdef EPROTOTYPE
else if (e==EPROTOTYPE) { Mr MA_BAD_PROTOCOL; }
#endif
#ifdef ENOPROTOOPT
else if (e==ENOPROTOOPT) { Mr MA_PROTOCOL_UNAVAILABLE; }
#endif
#ifdef EPROTONOSUPPORT
else if (e==EPROTONOSUPPORT) { Mr MA_PROTOCOL_NOT_SUPPORTED; }
#endif
#ifdef ESOCKTNOSUPPORT
else if (e==ESOCKTNOSUPPORT) { Mr MA_SOCKET_NOT_SUPPORTED; }
#endif
#ifdef EOPNOTSUPP
else if (e==EOPNOTSUPP) { Mr MA_INVALID_OPERATION; }
#endif
#ifdef EPFNOSUPPORT
else if (e==EPFNOSUPPORT) { Mr MA_PROTOCOL_FAMILY_NOT_SUPPORTED; }
#endif
#ifdef EAFNOSUPPORT
else if (e==EAFNOSUPPORT) { Mr MA_ADDRESS_FAMILY_NOT_SUPPORTED; }
#endif
#ifdef EADDRINUSE
else if (e==EADDRINUSE) { Mr MA_ALREADY_IN_USE; }
#endif
#ifdef EADDRNOTAVAIL
else if (e==EADDRNOTAVAIL) { Mr MA_ERROR; }
#endif
#ifdef ENETDOWN
else if (e==ENETDOWN) { Mr MA_NO_NETWORK; }
#endif
#ifdef ENETUNREACH
else if (e==ENETUNREACH) { Mr MA_NO_NETWORK; }
#endif
#ifdef ENETRESET
else if (e==ENETRESET) { Mr MA_NO_NETWORK; }
#endif
#ifdef ECONNABORTED
else if (e==ECONNABORTED) { Mr MA_NO_NETWORK; }
#endif
#ifdef ECONNRESET
else if (e==ECONNRESET) { Mr MA_CONNECTION_RESET; }
#endif
#ifdef ENOBUFS
else if (e==ENOBUFS) { Mr MA_NO_SPACE; }
#endif
#ifdef EISCONN
else if (e==EISCONN) { Mr MA_ALREADY_CONNECTED; }
#endif
#ifdef ENOTCONN
else if (e==ENOTCONN) { Mr MA_NOT_CONNECTED; }
#endif
#ifdef ESHUTDOWN
else if (e==ESHUTDOWN) { Mr MA_ERROR; }
#endif
#ifdef ETOOMANYREFS
else if (e==ETOOMANYREFS) { Mr MA_ERROR; }
#endif
#ifdef ETIMEDOUT
else if (e==ETIMEDOUT) { Mr MA_TIMEOUT; }
#endif
#ifdef ECONNREFUSED
else if (e==ECONNREFUSED) { Mr MA_CONNECTION_REFUSED; }
#endif
#ifdef EHOSTDOWN
else if (e==EHOSTDOWN) { Mr MA_NO_HOST; }
#endif
#ifdef EHOSTUNREACH
else if (e==EHOSTUNREACH) { Mr MA_NO_HOST; }
#endif
#ifdef EALREADY
else if (e==EALREADY) { Mr MA_IN_PROGRESS; }
#endif
#ifdef EINPROGRESS
else if (e==EINPROGRESS) { Mr MA_IN_PROGRESS; }
#endif
#ifdef ESTALE
else if (e==ESTALE) { Mr MA_INVALID_FILE; }
#endif
#ifdef EUCLEAN
else if (e==EUCLEAN) { Mr MA_ERROR; }
#endif
#ifdef ENOTNAM
else if (e==ENOTNAM) { Mr MA_ERROR; }
#endif
#ifdef ENAVAIL
else if (e==ENAVAIL) { Mr MA_ERROR; }
#endif
#ifdef EISNAM
else if (e==EISNAM) { Mr MA_ERROR; }
#endif
#ifdef EREMOTEIO
else if (e==EREMOTEIO) { Mr MA_IO_ERROR; }
#endif
#ifdef EDQUOT
else if (e==EDQUOT) { Mr MA_NO_SPACE; }
#endif
#ifdef ENOMEDIUM
else if (e==ENOMEDIUM) { Mr MA_DOES_NOT_EXIST; }
#endif
#ifdef EMEDIUMTYPE
else if (e==EMEDIUMTYPE) { Mr MA_ERROR; }
#endif
#ifdef ECANCELED
else if (e==ECANCELED) { Mr MA_CANCELLED; }
#endif
#ifdef ENOKEY
else if (e==ENOKEY) { Mr MA_ERROR; }
#endif
#ifdef EKEYEXPIRED
else if (e==EKEYEXPIRED) { Mr MA_ERROR; }
#endif
#ifdef EKEYREVOKED
else if (e==EKEYREVOKED) { Mr MA_ERROR; }
#endif
#ifdef EKEYREJECTED
else if (e==EKEYREJECTED) { Mr MA_ERROR; }
#endif
#ifdef EOWNERDEAD
else if (e==EOWNERDEAD) { Mr MA_ERROR; }
#endif
#ifdef ENOTRECOVERABLE
else if (e==ENOTRECOVERABLE) { Mr MA_ERROR; }
#endif
#ifdef ERFKILL
else if (e==ERFKILL) { Mr MA_ERROR; }
#endif
#ifdef EHWPOISON
else if (e==EHWPOISON) { Mr MA_ERROR; }
#endif
else {
Mr MA_ERROR;
}
}
MA_API Me ma_fopen(FILE**ppFile,const char*pFilePath,const char*pOpenMode)
{
#if defined(_MSC_VER)&&_MSC_VER>=1400
errno_t err;
#endif
if (ppFile !=NULL) {
*ppFile=NULL;
}
if (pFilePath==NULL||pOpenMode==NULL||ppFile==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(_MSC_VER)&&_MSC_VER>=1400
err=fopen_s(ppFile,pFilePath,pOpenMode);
if (err !=0) {
Mr ma_result_from_errno(err);
}
#else
#if defined(_WIN32)||defined(__APPLE__)
*ppFile=fopen(pFilePath,pOpenMode);
#else
#if defined(_FILE_OFFSET_BITS)&&_FILE_OFFSET_BITS==64&&defined(_LARGEFILE64_SOURCE)
*ppFile=fopen64(pFilePath,pOpenMode);
#else
*ppFile=fopen(pFilePath,pOpenMode);
#endif
#endif
if (*ppFile==NULL) {
Me Mf=ma_result_from_errno(errno);
if (Mf==Ms) {
Mf=MA_ERROR;
}
Mr Mf;
}
#endif
Mr Ms;
}
#if defined(_WIN32)
#if defined(_MSC_VER)||defined(__MINGW64__)||(!defined(__STRICT_ANSI__)&&!defined(_NO_EXT_KEYS))
#define MA_HAS_WFOPEN
#endif
#endif
MA_API Me ma_wfopen(FILE**ppFile,const wchar_t*pFilePath,const wchar_t*pOpenMode,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (ppFile !=NULL) {
*ppFile=NULL;
}
if (pFilePath==NULL||pOpenMode==NULL||ppFile==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_HAS_WFOPEN)
{
#if defined(_MSC_VER)&&_MSC_VER>=1400
errno_t err=_wfopen_s(ppFile,pFilePath,pOpenMode);
if (err !=0) {
Mr ma_result_from_errno(err);
}
#else
*ppFile=_wfopen(pFilePath,pOpenMode);
if (*ppFile==NULL) {
Mr ma_result_from_errno(errno);
}
#endif
(Mv)pAllocationCallbacks;
}
#else
{
mbstate_t mbs;
size_t lenMB;
const wchar_t*pFilePathTemp=pFilePath;
char*pFilePathMB=NULL;
char pOpenModeMB[32]={0};
MA_ZERO_OBJECT(&mbs);
lenMB=wcsrtombs(NULL,&pFilePathTemp,0,&mbs);
if (lenMB==(size_t)-1) {
Mr ma_result_from_errno(errno);
}
pFilePathMB=(char*)ma_malloc(lenMB+1,pAllocationCallbacks);
if (pFilePathMB==NULL) {
Mr MA_OUT_OF_MEMORY;
}
pFilePathTemp=pFilePath;
MA_ZERO_OBJECT(&mbs);
wcsrtombs(pFilePathMB,&pFilePathTemp,lenMB+1,&mbs);
{
size_t i=0;
for (;;) {
if (pOpenMode[i]==0) {
 pOpenModeMB[i]='\0';
 break;
}
pOpenModeMB[i]=(char)pOpenMode[i];
i+=1;
}
}
*ppFile=fopen(pFilePathMB,pOpenModeMB);
ma_free(pFilePathMB,pAllocationCallbacks);
}
if (*ppFile==NULL) {
Mr MA_ERROR;
}
#endif
Mr Ms;
}
static MA_INLINE Mv ma_copy_memory_64(Mv*dst,const Mv*src,M6 sizeInBytes)
{
#if 0xFFFFFFFFFFFFFFFF<=MA_SIZE_MAX
MA_COPY_MEMORY(dst,src,(size_t)sizeInBytes);
#else
while (sizeInBytes>0) {
M6 bytesToCopyNow=sizeInBytes;
if (bytesToCopyNow>MA_SIZE_MAX) {
bytesToCopyNow=MA_SIZE_MAX;
}
MA_COPY_MEMORY(dst,src,(size_t)bytesToCopyNow);
sizeInBytes-=bytesToCopyNow;
dst=( Mv*)(( ma_uint8*)dst+bytesToCopyNow);
src=(const Mv*)((const ma_uint8*)src+bytesToCopyNow);
}
#endif
}
static MA_INLINE Mv ma_zero_memory_64(Mv*dst,M6 sizeInBytes)
{
#if 0xFFFFFFFFFFFFFFFF<=MA_SIZE_MAX
MA_ZERO_MEMORY(dst,(size_t)sizeInBytes);
#else
while (sizeInBytes>0) {
M6 bytesToZeroNow=sizeInBytes;
if (bytesToZeroNow>MA_SIZE_MAX) {
bytesToZeroNow=MA_SIZE_MAX;
}
MA_ZERO_MEMORY(dst,(size_t)bytesToZeroNow);
sizeInBytes-=bytesToZeroNow;
dst=(Mv*)((ma_uint8*)dst+bytesToZeroNow);
}
#endif
}
static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x)
{
x--;
x|=x>>1;
x|=x>>2;
x|=x>>4;
x|=x>>8;
x|=x>>16;
x++;
Mr x;
}
static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x)
{
Mr ma_next_power_of_2(x)>>1;
}
static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x)
{
unsigned int prev=ma_prev_power_of_2(x);
unsigned int next=ma_next_power_of_2(x);
if ((next-x)>(x-prev)) {
Mr prev;
} else {
Mr next;
}
}
static MA_INLINE unsigned int ma_count_set_bits(unsigned int x)
{
unsigned int count=0;
while (x !=0) {
if (x&1) {
count+=1;
}
x=x>>1;
}
Mr count;
}
static Mv*ma__malloc_default(size_t sz,Mv*pUserData)
{
(Mv)pUserData;
Mr MA_MALLOC(sz);
}
static Mv*ma__realloc_default(Mv*p,size_t sz,Mv*pUserData)
{
(Mv)pUserData;
Mr MA_REALLOC(p,sz);
}
static Mv ma__free_default(Mv*p,Mv*pUserData)
{
(Mv)pUserData;
MA_FREE(p);
}
static ma_allocation_callbacks ma_allocation_callbacks_init_default(Mv)
{
ma_allocation_callbacks callbacks;
callbacks.pUserData=NULL;
callbacks.onMalloc=ma__malloc_default;
callbacks.onRealloc=ma__realloc_default;
callbacks.onFree=ma__free_default;
Mr callbacks;
}
static Me ma_allocation_callbacks_init_copy(ma_allocation_callbacks*pDst,const ma_allocation_callbacks*pSrc)
{
if (pDst==NULL) {
Mr MA_INVALID_ARGS;
}
if (pSrc==NULL) {
*pDst=ma_allocation_callbacks_init_default();
} else {
if (pSrc->pUserData==NULL&&pSrc->onFree==NULL&&pSrc->onMalloc==NULL&&pSrc->onRealloc==NULL) {
*pDst=ma_allocation_callbacks_init_default();
} else {
if (pSrc->onFree==NULL||(pSrc->onMalloc==NULL&&pSrc->onRealloc==NULL)) {
Mr MA_INVALID_ARGS;
} else {
*pDst=*pSrc;
}
}
}
Mr Ms;
}
MA_API const char*ma_log_level_to_string(M3 logLevel)
{
switch (logLevel)
{
case MA_LOG_LEVEL_DEBUG: Mr "DEBUG";
case MA_LOG_LEVEL_INFO: Mr "INFO";
case MA_LOG_LEVEL_WARNING: Mr "WARNING";
case MA_LOG_LEVEL_ERROR: Mr "ERROR";
default: Mr "ERROR";
}
}
#if defined(MA_DEBUG_OUTPUT)
#if defined(MA_ANDROID)
#include <android/log.h>
#endif
#ifndef MA_ANDROID_LOG_TAG
#define MA_ANDROID_LOG_TAG "miniaudio"
#endif
Mv ma_log_callback_debug(Mv*pUserData,M3 level,const char*pMessage)
{
(Mv)pUserData;
#if defined(MA_ANDROID)
{
__android_log_print(ANDROID_LOG_DEBUG, MA_ANDROID_LOG_TAG, "%s: %s", ma_log_level_to_string(level), pMessage);
}
#else
{
printf("%s: %s", ma_log_level_to_string(level), pMessage);
}
#endif
}
#endif
MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog,Mv*pUserData)
{
ma_log_callback callback;
MA_ZERO_OBJECT(&callback);
callback.onLog=onLog;
callback.pUserData=pUserData;
Mr callback;
}
MA_API Me ma_log_init(const ma_allocation_callbacks*pAllocationCallbacks,ma_log*pLog)
{
if (pLog==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLog);
ma_allocation_callbacks_init_copy(&pLog->allocationCallbacks,pAllocationCallbacks);
#ifndef MA_NO_THREADING
{
Me Mf=ma_mutex_init(&pLog->lock);
if (Mf !=Ms) {
Mr Mf;
}
}
#endif
#if defined(MA_DEBUG_OUTPUT)
{
ma_log_register_callback(pLog,ma_log_callback_init(ma_log_callback_debug,NULL));
}
#endif
Mr Ms;
}
MA_API Mv ma_log_uninit(ma_log*pLog)
{
if (pLog==NULL) {
Mr;
}
#ifndef MA_NO_THREADING
ma_mutex_uninit(&pLog->lock);
#endif
}
static Mv ma_log_lock(ma_log*pLog)
{
#ifndef MA_NO_THREADING
ma_mutex_lock(&pLog->lock);
#else
(Mv)pLog;
#endif
}
static Mv ma_log_unlock(ma_log*pLog)
{
#ifndef MA_NO_THREADING
ma_mutex_unlock(&pLog->lock);
#else
(Mv)pLog;
#endif
}
MA_API Me ma_log_register_callback(ma_log*pLog,ma_log_callback callback)
{
Me Mf=Ms;
if (pLog==NULL||callback.onLog==NULL) {
Mr MA_INVALID_ARGS;
}
ma_log_lock(pLog);
{
if (pLog->callbackCount==ma_countof(pLog->callbacks)) {
Mf=MA_OUT_OF_MEMORY;
} else {
pLog->callbacks[pLog->callbackCount]=callback;
pLog->callbackCount+=1;
}
}
ma_log_unlock(pLog);
Mr Mf;
}
MA_API Me ma_log_unregister_callback(ma_log*pLog,ma_log_callback callback)
{
if (pLog==NULL) {
Mr MA_INVALID_ARGS;
}
ma_log_lock(pLog);
{
M3 iLog;
for (iLog=0; iLog<pLog->callbackCount; ) {
if (pLog->callbacks[iLog].onLog==callback.onLog) {
M3 jLog;
for (jLog=iLog; jLog<pLog->callbackCount-1; jLog+=1) {
 pLog->callbacks[jLog]=pLog->callbacks[jLog+1];
}
pLog->callbackCount-=1;
} else {
iLog+=1;
}
}
}
ma_log_unlock(pLog);
Mr Ms;
}
MA_API Me ma_log_post(ma_log*pLog,M3 level,const char*pMessage)
{
if (pLog==NULL||pMessage==NULL) {
Mr MA_INVALID_ARGS;
}
ma_log_lock(pLog);
{
M3 iLog;
for (iLog=0; iLog<pLog->callbackCount; iLog+=1) {
if (pLog->callbacks[iLog].onLog) {
pLog->callbacks[iLog].onLog(pLog->callbacks[iLog].pUserData,level,pMessage);
}
}
}
ma_log_unlock(pLog);
Mr Ms;
}
#if defined(_MSC_VER)&&_MSC_VER<1900
static int ma_vscprintf(const ma_allocation_callbacks*pAllocationCallbacks,const char*format,va_list args)
{
#if _MSC_VER>1200
Mr _vscprintf(format,args);
#else
int Mf;
char*pTempBuffer=NULL;
size_t tempBufferCap=1024;
if (format==NULL) {
errno=EINVAL;
Mr-1;
}
for (;;) {
char*pNewTempBuffer=(char*)ma_realloc(pTempBuffer,tempBufferCap,pAllocationCallbacks);
if (pNewTempBuffer==NULL) {
ma_free(pTempBuffer,pAllocationCallbacks);
errno=ENOMEM;
Mr-1;
}
pTempBuffer=pNewTempBuffer;
Mf=_vsnprintf(pTempBuffer,tempBufferCap,format,args);
ma_free(pTempBuffer,NULL);
if (Mf !=-1) {
break;
}
tempBufferCap*=2;
}
Mr Mf;
#endif
}
#endif
MA_API Me ma_log_postv(ma_log*pLog,M3 level,const char*pFormat,va_list args)
{
if (pLog==NULL||pFormat==NULL) {
Mr MA_INVALID_ARGS;
}
#if (defined(__STDC_VERSION__)&&__STDC_VERSION__>=199901L)||((!defined(_MSC_VER)||_MSC_VER>=1900)&&!defined(__STRICT_ANSI__)&&!defined(_NO_EXT_KEYS))||(defined(__cplusplus)&&__cplusplus>=201103L)
{
Me Mf;
int length;
char pFormattedMessageStack[1024];
char*pFormattedMessageHeap=NULL;
length=vsnprintf(pFormattedMessageStack,sizeof(pFormattedMessageStack),pFormat,args);
if (length<0) {
Mr MA_INVALID_OPERATION;
}
if ((size_t)length<sizeof(pFormattedMessageStack)) {
Mf=ma_log_post(pLog,level,pFormattedMessageStack);
} else {
pFormattedMessageHeap=(char*)ma_malloc(length+1,&pLog->allocationCallbacks);
if (pFormattedMessageHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
length=vsnprintf(pFormattedMessageHeap,length+1,pFormat,args);
if (length<0) {
ma_free(pFormattedMessageHeap,&pLog->allocationCallbacks);
Mr MA_INVALID_OPERATION;
}
Mf=ma_log_post(pLog,level,pFormattedMessageHeap);
ma_free(pFormattedMessageHeap,&pLog->allocationCallbacks);
}
Mr Mf;
}
#else
{
#if defined(_MSC_VER)&&_MSC_VER>=1200
{
Me Mf;
int formattedLen;
char*pFormattedMessage=NULL;
va_list args2;
#if _MSC_VER>=1800
{
va_copy(args2,args);
}
#else
{
args2=args;
}
#endif
formattedLen=ma_vscprintf(&pLog->allocationCallbacks,pFormat,args2);
va_end(args2);
if (formattedLen<=0) {
Mr MA_INVALID_OPERATION;
}
pFormattedMessage=(char*)ma_malloc(formattedLen+1,&pLog->allocationCallbacks);
if (pFormattedMessage==NULL) {
Mr MA_OUT_OF_MEMORY;
}
#if _MSC_VER>=1400
{
vsprintf_s(pFormattedMessage,formattedLen+1,pFormat,args);
}
#else
{
vsprintf(pFormattedMessage,pFormat,args);
}
#endif
Mf=ma_log_post(pLog,level,pFormattedMessage);
ma_free(pFormattedMessage,&pLog->allocationCallbacks);
Mr Mf;
}
#else
{
(Mv)level;
(Mv)args;
Mr MA_INVALID_OPERATION;
}
#endif
}
#endif
}
MA_API Me ma_log_postf(ma_log*pLog,M3 level,const char*pFormat,...)
{
Me Mf;
va_list args;
if (pLog==NULL||pFormat==NULL) {
Mr MA_INVALID_ARGS;
}
va_start(args,pFormat);
{
Mf=ma_log_postv(pLog,level,pFormat,args);
}
va_end(args);
Mr Mf;
}
static MA_INLINE ma_uint8 ma_clip_u8(ma_int32 x)
{
Mr (ma_uint8)(ma_clamp(x,-128,127)+128);
}
static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x)
{
Mr (ma_int16)ma_clamp(x,-32768,32767);
}
static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x)
{
Mr (ma_int64)ma_clamp(x,-8388608,8388607);
}
static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x)
{
ma_int64 clipMin;
ma_int64 clipMax;
clipMin=-((ma_int64)2147483647+1);
clipMax=(ma_int64)2147483647;
Mr (ma_int32)ma_clamp(x,clipMin,clipMax);
}
static MA_INLINE float ma_clip_f32(float x)
{
if (x<-1) Mr-1;
if (x>+1) Mr+1;
Mr x;
}
static MA_INLINE float ma_mix_f32(float x,float y,float a)
{
Mr x*(1-a)+y*a;
}
static MA_INLINE float ma_mix_f32_fast(float x,float y,float a)
{
float r0=(y-x);
float r1=r0*a;
Mr x+r1;
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x,__m128 y,__m128 a)
{
Mr _mm_add_ps(x,_mm_mul_ps(_mm_sub_ps(y,x),a));
}
#endif
#if defined(MA_SUPPORT_AVX2)
static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x,__m256 y,__m256 a)
{
Mr _mm256_add_ps(x,_mm256_mul_ps(_mm256_sub_ps(y,x),a));
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x,float32x4_t y,float32x4_t a)
{
Mr vaddq_f32(x,vmulq_f32(vsubq_f32(y,x),a));
}
#endif
static MA_INLINE double ma_mix_f64(double x,double y,double a)
{
Mr x*(1-a)+y*a;
}
static MA_INLINE double ma_mix_f64_fast(double x,double y,double a)
{
Mr x+(y-x)*a;
}
static MA_INLINE float ma_scale_to_range_f32(float x,float lo,float hi)
{
Mr lo+x*(hi-lo);
}
static MA_INLINE M3 ma_gcf_u32(M3 a,M3 b)
{
for (;;) {
if (b==0) {
break;
} else {
M3 t=a;
a=b;
b=t % a;
}
}
Mr a;
}
static M3 ma_ffs_32(M3 x)
{
M3 i;
for (i=0; i<32; i+=1) {
if ((x&(1U<<i)) !=0) {
Mr i;
}
}
Mr i;
}
static MA_INLINE ma_int16 ma_float_to_fixed_16(float x)
{
Mr (ma_int16)(x*(1<<8));
}
#ifndef MA_DEFAULT_LCG_SEED
#define MA_DEFAULT_LCG_SEED 4321
#endif
#define MA_LCG_M 2147483647
#define MA_LCG_A 48271
#define MA_LCG_C 0
static ma_lcg g_maLCG={MA_DEFAULT_LCG_SEED};
static MA_INLINE Mv ma_lcg_seed(ma_lcg*pLCG,ma_int32 seed)
{
MA_ASSERT(pLCG !=NULL);
pLCG->state=seed;
}
static MA_INLINE ma_int32 ma_lcg_rand_s32(ma_lcg*pLCG)
{
pLCG->state=(MA_LCG_A*pLCG->state+MA_LCG_C) % MA_LCG_M;
Mr pLCG->state;
}
static MA_INLINE M3 ma_lcg_rand_u32(ma_lcg*pLCG)
{
Mr (M3)ma_lcg_rand_s32(pLCG);
}
static MA_INLINE ma_int16 ma_lcg_rand_s16(ma_lcg*pLCG)
{
Mr (ma_int16)(ma_lcg_rand_s32(pLCG)&0xFFFF);
}
static MA_INLINE double ma_lcg_rand_f64(ma_lcg*pLCG)
{
Mr ma_lcg_rand_s32(pLCG) / (double)0x7FFFFFFF;
}
static MA_INLINE float ma_lcg_rand_f32(ma_lcg*pLCG)
{
Mr (float)ma_lcg_rand_f64(pLCG);
}
static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg*pLCG,float lo,float hi)
{
Mr ma_scale_to_range_f32(ma_lcg_rand_f32(pLCG),lo,hi);
}
static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg*pLCG,ma_int32 lo,ma_int32 hi)
{
if (lo==hi) {
Mr lo;
}
Mr lo+ma_lcg_rand_u32(pLCG) / (0xFFFFFFFF / (hi-lo+1)+1);
}
static MA_INLINE Mv ma_seed(ma_int32 seed)
{
ma_lcg_seed(&g_maLCG,seed);
}
static MA_INLINE ma_int32 ma_rand_s32(Mv)
{
Mr ma_lcg_rand_s32(&g_maLCG);
}
static MA_INLINE M3 ma_rand_u32(Mv)
{
Mr ma_lcg_rand_u32(&g_maLCG);
}
static MA_INLINE double ma_rand_f64(Mv)
{
Mr ma_lcg_rand_f64(&g_maLCG);
}
static MA_INLINE float ma_rand_f32(Mv)
{
Mr ma_lcg_rand_f32(&g_maLCG);
}
static MA_INLINE float ma_rand_range_f32(float lo,float hi)
{
Mr ma_lcg_rand_range_f32(&g_maLCG,lo,hi);
}
static MA_INLINE ma_int32 ma_rand_range_s32(ma_int32 lo,ma_int32 hi)
{
Mr ma_lcg_rand_range_s32(&g_maLCG,lo,hi);
}
static MA_INLINE float ma_dither_f32_rectangle(float ditherMin,float ditherMax)
{
Mr ma_rand_range_f32(ditherMin,ditherMax);
}
static MA_INLINE float ma_dither_f32_triangle(float ditherMin,float ditherMax)
{
float a=ma_rand_range_f32(ditherMin,0);
float b=ma_rand_range_f32(0,ditherMax);
Mr a+b;
}
static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode,float ditherMin,float ditherMax)
{
if (ditherMode==ma_dither_mode_rectangle) {
Mr ma_dither_f32_rectangle(ditherMin,ditherMax);
}
if (ditherMode==ma_dither_mode_triangle) {
Mr ma_dither_f32_triangle(ditherMin,ditherMax);
}
Mr 0;
}
static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode,ma_int32 ditherMin,ma_int32 ditherMax)
{
if (ditherMode==ma_dither_mode_rectangle) {
ma_int32 a=ma_rand_range_s32(ditherMin,ditherMax);
Mr a;
}
if (ditherMode==ma_dither_mode_triangle) {
ma_int32 a=ma_rand_range_s32(ditherMin,0);
ma_int32 b=ma_rand_range_s32(0,ditherMax);
Mr a+b;
}
Mr 0;
}
#ifndef ma_atomic_h
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc++11-long-long"
#endif
#endif
typedef int ma_atomic_memory_order;
#define MA_ATOMIC_HAS_8
#define MA_ATOMIC_HAS_16
#define MA_ATOMIC_HAS_32
#define MA_ATOMIC_HAS_64
#if (defined(_MSC_VER) )||defined(__WATCOMC__)||defined(__DMC__)
#define MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,intrin,ma_atomicType,msvcType)\
ma_atomicType Mf;\
switch (order)\
{\
case ma_atomic_memory_order_relaxed:\
{\
Mf=(ma_atomicType)intrin##_nf((volatile msvcType*)dst,(msvcType)src);\
} break;\
case ma_atomic_memory_order_consume:\
case ma_atomic_memory_order_acquire:\
{\
Mf=(ma_atomicType)intrin##_acq((volatile msvcType*)dst,(msvcType)src);\
} break;\
case ma_atomic_memory_order_release:\
{\
Mf=(ma_atomicType)intrin##_rel((volatile msvcType*)dst,(msvcType)src);\
} break;\
case ma_atomic_memory_order_acq_rel:\
case ma_atomic_memory_order_seq_cst:\
default:\
{\
Mf=(ma_atomicType)intrin((volatile msvcType*)dst,(msvcType)src);\
} break;\
}\
Mr Mf;
#define MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr,expected,desired,order,intrin,ma_atomicType,msvcType)\
ma_atomicType Mf;\
switch (order)\
{\
case ma_atomic_memory_order_relaxed:\
{\
Mf=(ma_atomicType)intrin##_nf((volatile msvcType*)ptr,(msvcType)expected,(msvcType)desired);\
} break;\
case ma_atomic_memory_order_consume:\
case ma_atomic_memory_order_acquire:\
{\
Mf=(ma_atomicType)intrin##_acq((volatile msvcType*)ptr,(msvcType)expected,(msvcType)desired);\
} break;\
case ma_atomic_memory_order_release:\
{\
Mf=(ma_atomicType)intrin##_rel((volatile msvcType*)ptr,(msvcType)expected,(msvcType)desired);\
} break;\
case ma_atomic_memory_order_acq_rel:\
case ma_atomic_memory_order_seq_cst:\
default:\
{\
Mf=(ma_atomicType)intrin((volatile msvcType*)ptr,(msvcType)expected,(msvcType)desired);\
} break;\
}\
Mr Mf;
#define ma_atomic_memory_order_relaxed 0
#define ma_atomic_memory_order_consume 1
#define ma_atomic_memory_order_acquire 2
#define ma_atomic_memory_order_release 3
#define ma_atomic_memory_order_acq_rel 4
#define ma_atomic_memory_order_seq_cst 5
#if _MSC_VER<1600&&defined(MA_X86)
#define MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY
#endif
#if _MSC_VER<1600
#undef MA_ATOMIC_HAS_8
#undef MA_ATOMIC_HAS_16
#endif
#if !defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
#include <intrin.h>
#endif
#if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_compare_and_swap_8(volatile ma_uint8*dst,ma_uint8 expected,ma_uint8 desired)
{
ma_uint8 Mf=0;
__asm {
 mov ecx,dst
 mov al,expected
 mov dl,desired
 lock cmpxchg [ecx],dl
 mov Mf,al
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_compare_and_swap_16(volatile ma_uint16*dst,ma_uint16 expected,ma_uint16 desired)
{
ma_uint16 Mf=0;
__asm {
 mov ecx,dst
 mov ax,expected
 mov dx,desired
 lock cmpxchg [ecx],dx
 mov Mf,ax
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_compare_and_swap_32(volatile M3*dst,M3 expected,M3 desired)
{
M3 Mf=0;
__asm {
 mov ecx,dst
 mov eax,expected
 mov edx,desired
 lock cmpxchg [ecx],edx
 mov Mf,eax
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE M6 __stdcall ma_atomic_compare_and_swap_64(volatile M6*dst,M6 expected,M6 desired)
{
M3 resultEAX=0;
M3 resultEDX=0;
__asm {
 mov esi,dst
 mov eax,dword ptr expected
 mov edx,dword ptr expected+4
 mov ebx,dword ptr desired
 mov ecx,dword ptr desired+4
 lock cmpxchg8b qword ptr [esi]
 mov resultEAX,eax
 mov resultEDX,edx
}
Mr ((M6)resultEDX<<32)|resultEAX;
}
#endif
#else
#if defined(MA_ATOMIC_HAS_8)
#define ma_atomic_compare_and_swap_8( dst,expected,desired) (ma_uint8 )_InterlockedCompareExchange8((volatile char*)dst,(char)desired,(char)expected)
#endif
#if defined(MA_ATOMIC_HAS_16)
#define ma_atomic_compare_and_swap_16(dst,expected,desired) (ma_uint16)_InterlockedCompareExchange16((volatile short*)dst,(short)desired,(short)expected)
#endif
#if defined(MA_ATOMIC_HAS_32)
#define ma_atomic_compare_and_swap_32(dst,expected,desired) (M3)_InterlockedCompareExchange((volatile long*)dst,(long)desired,(long)expected)
#endif
#if defined(MA_ATOMIC_HAS_64)
#define ma_atomic_compare_and_swap_64(dst,expected,desired) (M6)_InterlockedCompareExchange64((volatile ma_int64*)dst,(ma_int64)desired,(ma_int64)expected)
#endif
#endif
#if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 Mf=0;
(Mv)order;
__asm {
 mov ecx,dst
 mov al,src
 lock xchg [ecx],al
 mov Mf,al
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 Mf=0;
(Mv)order;
__asm {
 mov ecx,dst
 mov ax,src
 lock xchg [ecx],ax
 mov Mf,ax
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_exchange_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 Mf=0;
(Mv)order;
__asm {
 mov ecx,dst
 mov eax,src
 lock xchg [ecx],eax
 mov Mf,eax
}
Mr Mf;
}
#endif
#else
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_exchange_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchange8,ma_uint8,char);
#else
(Mv)order;
Mr (ma_uint8)_InterlockedExchange8((volatile char*)dst,(char)src);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_exchange_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchange16,ma_uint16,short);
#else
(Mv)order;
Mr (ma_uint16)_InterlockedExchange16((volatile short*)dst,(short)src);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_exchange_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchange,M3,long);
#else
(Mv)order;
Mr (M3)_InterlockedExchange((volatile long*)dst,(long)src);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_64)&&defined(MA_64BIT)
static MA_INLINE M6 __stdcall ma_atomic_exchange_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchange64,M6,long long);
#else
(Mv)order;
Mr (M6)_InterlockedExchange64((volatile long long*)dst,(long long)src);
#endif
}
#else
#endif
#endif
#if defined(MA_ATOMIC_HAS_64)&&!defined(MA_64BIT)
static MA_INLINE M6 __stdcall ma_atomic_exchange_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
do {
oldValue=*dst;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,src) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 Mf=0;
(Mv)order;
__asm {
 mov ecx,dst
 mov al,src
 lock xadd [ecx],al
 mov Mf,al
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 Mf=0;
(Mv)order;
__asm {
 mov ecx,dst
 mov ax,src
 lock xadd [ecx],ax
 mov Mf,ax
}
Mr Mf;
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_fetch_add_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 Mf=0;
(Mv)order;
__asm {
 mov ecx,dst
 mov eax,src
 lock xadd [ecx],eax
 mov Mf,eax
}
Mr Mf;
}
#endif
#else
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_add_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchangeAdd8,ma_uint8,char);
#else
(Mv)order;
Mr (ma_uint8)_InterlockedExchangeAdd8((volatile char*)dst,(char)src);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_add_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchangeAdd16,ma_uint16,short);
#else
(Mv)order;
Mr (ma_uint16)_InterlockedExchangeAdd16((volatile short*)dst,(short)src);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_fetch_add_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchangeAdd,M3,long);
#else
(Mv)order;
Mr (M3)_InterlockedExchangeAdd((volatile long*)dst,(long)src);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_64)&&defined(MA_64BIT)
static MA_INLINE M6 __stdcall ma_atomic_fetch_add_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedExchangeAdd64,M6,long long);
#else
(Mv)order;
Mr (M6)_InterlockedExchangeAdd64((volatile long long*)dst,(long long)src);
#endif
}
#else
#endif
#endif
#if defined(MA_ATOMIC_HAS_64)&&!defined(MA_64BIT)
static MA_INLINE M6 __stdcall ma_atomic_fetch_add_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue+src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#if defined(MA_ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
static MA_INLINE Mv __stdcall ma_atomic_thread_fence(ma_atomic_memory_order order)
{
(Mv)order;
__asm {
lock add [esp],0
}
}
#else
#if defined(MA_X64)
#define ma_atomic_thread_fence(order) __faststorefence(),(Mv)order
#elif defined(MA_ARM64)
#define ma_atomic_thread_fence(order) __dmb(_ARM64_BARRIER_ISH),(Mv)order
#else
static MA_INLINE Mv ma_atomic_thread_fence(ma_atomic_memory_order order)
{
volatile M3 barrier=0;
ma_atomic_fetch_add_explicit_32(&barrier,0,order);
}
#endif
#endif
#define ma_atomic_compiler_fence() ma_atomic_thread_fence(ma_atomic_memory_order_seq_cst)
#define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order)
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8*ptr,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr,0,0,order,_InterlockedCompareExchange8,ma_uint8,char);
#else
(Mv)order;
Mr ma_atomic_compare_and_swap_8((volatile ma_uint8*)ptr,0,0);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16*ptr,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr,0,0,order,_InterlockedCompareExchange16,ma_uint16,short);
#else
(Mv)order;
Mr ma_atomic_compare_and_swap_16((volatile ma_uint16*)ptr,0,0);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 ma_atomic_load_explicit_32(volatile const M3*ptr,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr,0,0,order,_InterlockedCompareExchange,M3,long);
#else
(Mv)order;
Mr ma_atomic_compare_and_swap_32((volatile M3*)ptr,0,0);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE M6 ma_atomic_load_explicit_64(volatile const M6*ptr,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC_COMPARE_EXCHANGE(ptr,0,0,order,_InterlockedCompareExchange64,M6,long long);
#else
(Mv)order;
Mr ma_atomic_compare_and_swap_64((volatile M6*)ptr,0,0);
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_8)
#define ma_atomic_store_explicit_8( dst,src,order) (Mv)ma_atomic_exchange_explicit_8 (dst,src,order)
#endif
#if defined(MA_ATOMIC_HAS_16)
#define ma_atomic_store_explicit_16(dst,src,order) (Mv)ma_atomic_exchange_explicit_16(dst,src,order)
#endif
#if defined(MA_ATOMIC_HAS_32)
#define ma_atomic_store_explicit_32(dst,src,order) (Mv)ma_atomic_exchange_explicit_32(dst,src,order)
#endif
#if defined(MA_ATOMIC_HAS_64)
#define ma_atomic_store_explicit_64(dst,src,order) (Mv)ma_atomic_exchange_explicit_64(dst,src,order)
#endif
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_sub_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue-src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_sub_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue-src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_fetch_sub_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue-src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE M6 __stdcall ma_atomic_fetch_sub_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue-src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_and_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedAnd8,ma_uint8,char);
#else
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue&src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_and_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedAnd16,ma_uint16,short);
#else
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue&src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_fetch_and_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedAnd,M3,long);
#else
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue&src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE M6 __stdcall ma_atomic_fetch_and_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedAnd64,M6,long long);
#else
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue&src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_xor_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedXor8,ma_uint8,char);
#else
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue ^ src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_xor_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedXor16,ma_uint16,short);
#else
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue ^ src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_fetch_xor_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedXor,M3,long);
#else
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue ^ src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE M6 __stdcall ma_atomic_fetch_xor_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedXor64,M6,long long);
#else
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue ^ src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_uint8 __stdcall ma_atomic_fetch_or_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedOr8,ma_uint8,char);
#else
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue|src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_uint16 __stdcall ma_atomic_fetch_or_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedOr16,ma_uint16,short);
#else
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue|src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE M3 __stdcall ma_atomic_fetch_or_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedOr,M3,long);
#else
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue|src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE M6 __stdcall ma_atomic_fetch_or_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
#if defined(MA_ARM)
MA_ATOMIC_MSVC_ARM_INTRINSIC(dst,src,order,_InterlockedOr64,M6,long long);
#else
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue|src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
#endif
}
#endif
#if defined(MA_ATOMIC_HAS_8)
#define ma_atomic_test_and_set_explicit_8( dst,order) ma_atomic_exchange_explicit_8 (dst,1,order)
#endif
#if defined(MA_ATOMIC_HAS_16)
#define ma_atomic_test_and_set_explicit_16(dst,order) ma_atomic_exchange_explicit_16(dst,1,order)
#endif
#if defined(MA_ATOMIC_HAS_32)
#define ma_atomic_test_and_set_explicit_32(dst,order) ma_atomic_exchange_explicit_32(dst,1,order)
#endif
#if defined(MA_ATOMIC_HAS_64)
#define ma_atomic_test_and_set_explicit_64(dst,order) ma_atomic_exchange_explicit_64(dst,1,order)
#endif
#if defined(MA_ATOMIC_HAS_8)
#define ma_atomic_clear_explicit_8( dst,order) ma_atomic_store_explicit_8 (dst,0,order)
#endif
#if defined(MA_ATOMIC_HAS_16)
#define ma_atomic_clear_explicit_16(dst,order) ma_atomic_store_explicit_16(dst,0,order)
#endif
#if defined(MA_ATOMIC_HAS_32)
#define ma_atomic_clear_explicit_32(dst,order) ma_atomic_store_explicit_32(dst,0,order)
#endif
#if defined(MA_ATOMIC_HAS_64)
#define ma_atomic_clear_explicit_64(dst,order) ma_atomic_store_explicit_64(dst,0,order)
#endif
#if defined(MA_ATOMIC_HAS_8)
typedef ma_uint8 ma_atomic_flag;
#define ma_atomic_flag_test_and_set_explicit(ptr,order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr,order)
#define ma_atomic_flag_clear_explicit(ptr,order) ma_atomic_clear_explicit_8(ptr,order)
#define ma_atomic_flag_load_explicit(ptr,order) ma_atomic_load_explicit_8(ptr,order)
#else
typedef M3 ma_atomic_flag;
#define ma_atomic_flag_test_and_set_explicit(ptr,order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr,order)
#define ma_atomic_flag_clear_explicit(ptr,order) ma_atomic_clear_explicit_32(ptr,order)
#define ma_atomic_flag_load_explicit(ptr,order) ma_atomic_load_explicit_32(ptr,order)
#endif
#elif defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=7)))
#define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
#define MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE
#define ma_atomic_memory_order_relaxed __ATOMIC_RELAXED
#define ma_atomic_memory_order_consume __ATOMIC_CONSUME
#define ma_atomic_memory_order_acquire __ATOMIC_ACQUIRE
#define ma_atomic_memory_order_release __ATOMIC_RELEASE
#define ma_atomic_memory_order_acq_rel __ATOMIC_ACQ_REL
#define ma_atomic_memory_order_seq_cst __ATOMIC_SEQ_CST
#define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#define ma_atomic_thread_fence(order) __atomic_thread_fence(order)
#define ma_atomic_signal_fence(order) __atomic_signal_fence(order)
#define ma_atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1,ptr)
#define ma_atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2,ptr)
#define ma_atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4,ptr)
#define ma_atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8,ptr)
#define ma_atomic_test_and_set_explicit_8( dst,order) __atomic_exchange_n(dst,1,order)
#define ma_atomic_test_and_set_explicit_16(dst,order) __atomic_exchange_n(dst,1,order)
#define ma_atomic_test_and_set_explicit_32(dst,order) __atomic_exchange_n(dst,1,order)
#define ma_atomic_test_and_set_explicit_64(dst,order) __atomic_exchange_n(dst,1,order)
#define ma_atomic_clear_explicit_8( dst,order) __atomic_store_n(dst,0,order)
#define ma_atomic_clear_explicit_16(dst,order) __atomic_store_n(dst,0,order)
#define ma_atomic_clear_explicit_32(dst,order) __atomic_store_n(dst,0,order)
#define ma_atomic_clear_explicit_64(dst,order) __atomic_store_n(dst,0,order)
#define ma_atomic_store_explicit_8( dst,src,order) __atomic_store_n(dst,src,order)
#define ma_atomic_store_explicit_16(dst,src,order) __atomic_store_n(dst,src,order)
#define ma_atomic_store_explicit_32(dst,src,order) __atomic_store_n(dst,src,order)
#define ma_atomic_store_explicit_64(dst,src,order) __atomic_store_n(dst,src,order)
#define ma_atomic_load_explicit_8( dst,order) __atomic_load_n(dst,order)
#define ma_atomic_load_explicit_16(dst,order) __atomic_load_n(dst,order)
#define ma_atomic_load_explicit_32(dst,order) __atomic_load_n(dst,order)
#define ma_atomic_load_explicit_64(dst,order) __atomic_load_n(dst,order)
#define ma_atomic_exchange_explicit_8( dst,src,order) __atomic_exchange_n(dst,src,order)
#define ma_atomic_exchange_explicit_16(dst,src,order) __atomic_exchange_n(dst,src,order)
#define ma_atomic_exchange_explicit_32(dst,src,order) __atomic_exchange_n(dst,src,order)
#define ma_atomic_exchange_explicit_64(dst,src,order) __atomic_exchange_n(dst,src,order)
#define ma_atomic_compare_exchange_strong_explicit_8( dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,0,successOrder,failureOrder)
#define ma_atomic_compare_exchange_strong_explicit_16(dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,0,successOrder,failureOrder)
#define ma_atomic_compare_exchange_strong_explicit_32(dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,0,successOrder,failureOrder)
#define ma_atomic_compare_exchange_strong_explicit_64(dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,0,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_8( dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,1,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_16(dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,1,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_32(dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,1,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_64(dst,expected,desired,successOrder,failureOrder) __atomic_compare_exchange_n(dst,expected,desired,1,successOrder,failureOrder)
#define ma_atomic_fetch_add_explicit_8( dst,src,order) __atomic_fetch_add(dst,src,order)
#define ma_atomic_fetch_add_explicit_16(dst,src,order) __atomic_fetch_add(dst,src,order)
#define ma_atomic_fetch_add_explicit_32(dst,src,order) __atomic_fetch_add(dst,src,order)
#define ma_atomic_fetch_add_explicit_64(dst,src,order) __atomic_fetch_add(dst,src,order)
#define ma_atomic_fetch_sub_explicit_8( dst,src,order) __atomic_fetch_sub(dst,src,order)
#define ma_atomic_fetch_sub_explicit_16(dst,src,order) __atomic_fetch_sub(dst,src,order)
#define ma_atomic_fetch_sub_explicit_32(dst,src,order) __atomic_fetch_sub(dst,src,order)
#define ma_atomic_fetch_sub_explicit_64(dst,src,order) __atomic_fetch_sub(dst,src,order)
#define ma_atomic_fetch_or_explicit_8( dst,src,order) __atomic_fetch_or(dst,src,order)
#define ma_atomic_fetch_or_explicit_16(dst,src,order) __atomic_fetch_or(dst,src,order)
#define ma_atomic_fetch_or_explicit_32(dst,src,order) __atomic_fetch_or(dst,src,order)
#define ma_atomic_fetch_or_explicit_64(dst,src,order) __atomic_fetch_or(dst,src,order)
#define ma_atomic_fetch_xor_explicit_8( dst,src,order) __atomic_fetch_xor(dst,src,order)
#define ma_atomic_fetch_xor_explicit_16(dst,src,order) __atomic_fetch_xor(dst,src,order)
#define ma_atomic_fetch_xor_explicit_32(dst,src,order) __atomic_fetch_xor(dst,src,order)
#define ma_atomic_fetch_xor_explicit_64(dst,src,order) __atomic_fetch_xor(dst,src,order)
#define ma_atomic_fetch_and_explicit_8( dst,src,order) __atomic_fetch_and(dst,src,order)
#define ma_atomic_fetch_and_explicit_16(dst,src,order) __atomic_fetch_and(dst,src,order)
#define ma_atomic_fetch_and_explicit_32(dst,src,order) __atomic_fetch_and(dst,src,order)
#define ma_atomic_fetch_and_explicit_64(dst,src,order) __atomic_fetch_and(dst,src,order)
static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8*dst,ma_uint8 expected,ma_uint8 desired)
{
__atomic_compare_exchange_n(dst,&expected,desired,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST);
Mr expected;
}
static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16*dst,ma_uint16 expected,ma_uint16 desired)
{
__atomic_compare_exchange_n(dst,&expected,desired,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST);
Mr expected;
}
static MA_INLINE M3 ma_atomic_compare_and_swap_32(volatile M3*dst,M3 expected,M3 desired)
{
__atomic_compare_exchange_n(dst,&expected,desired,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST);
Mr expected;
}
#if defined(__clang__)
#pragma clang diagnostic push
#if __clang_major__>=8
#pragma clang diagnostic ignored "-Watomic-alignment"
#endif
#endif
static MA_INLINE M6 ma_atomic_compare_and_swap_64(volatile M6*dst,M6 expected,M6 desired)
{
__atomic_compare_exchange_n(dst,&expected,desired,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST);
Mr expected;
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
typedef ma_uint8 ma_atomic_flag;
#define ma_atomic_flag_test_and_set_explicit(dst,order) (ma_bool32)__atomic_test_and_set(dst,order)
#define ma_atomic_flag_clear_explicit(dst,order) __atomic_clear(dst,order)
#define ma_atomic_flag_load_explicit(ptr,order) ma_atomic_load_explicit_8(ptr,order)
#else
#define ma_atomic_memory_order_relaxed 1
#define ma_atomic_memory_order_consume 2
#define ma_atomic_memory_order_acquire 3
#define ma_atomic_memory_order_release 4
#define ma_atomic_memory_order_acq_rel 5
#define ma_atomic_memory_order_seq_cst 6
#define ma_atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#if defined(__GNUC__)
#define ma_atomic_thread_fence(order) __sync_synchronize(),(Mv)order
static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
if (order>ma_atomic_memory_order_acquire) {
__sync_synchronize();
}
Mr __sync_lock_test_and_set(dst,src);
}
static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 oldValue;
do {
oldValue=*dst;
} while (__sync_val_compare_and_swap(dst,oldValue,src) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M3 ma_atomic_exchange_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 oldValue;
do {
oldValue=*dst;
} while (__sync_val_compare_and_swap(dst,oldValue,src) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M6 ma_atomic_exchange_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
do {
oldValue=*dst;
} while (__sync_val_compare_and_swap(dst,oldValue,src) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_add(dst,src);
}
static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_add(dst,src);
}
static MA_INLINE M3 ma_atomic_fetch_add_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_add(dst,src);
}
static MA_INLINE M6 ma_atomic_fetch_add_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_add(dst,src);
}
static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_sub(dst,src);
}
static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_sub(dst,src);
}
static MA_INLINE M3 ma_atomic_fetch_sub_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_sub(dst,src);
}
static MA_INLINE M6 ma_atomic_fetch_sub_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_sub(dst,src);
}
static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_or(dst,src);
}
static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_or(dst,src);
}
static MA_INLINE M3 ma_atomic_fetch_or_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_or(dst,src);
}
static MA_INLINE M6 ma_atomic_fetch_or_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_or(dst,src);
}
static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_xor(dst,src);
}
static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_xor(dst,src);
}
static MA_INLINE M3 ma_atomic_fetch_xor_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_xor(dst,src);
}
static MA_INLINE M6 ma_atomic_fetch_xor_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_xor(dst,src);
}
static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_and(dst,src);
}
static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_and(dst,src);
}
static MA_INLINE M3 ma_atomic_fetch_and_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_and(dst,src);
}
static MA_INLINE M6 ma_atomic_fetch_and_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
(Mv)order;
Mr __sync_fetch_and_and(dst,src);
}
#define ma_atomic_compare_and_swap_8( dst,expected,desired) __sync_val_compare_and_swap(dst,expected,desired)
#define ma_atomic_compare_and_swap_16(dst,expected,desired) __sync_val_compare_and_swap(dst,expected,desired)
#define ma_atomic_compare_and_swap_32(dst,expected,desired) __sync_val_compare_and_swap(dst,expected,desired)
#define ma_atomic_compare_and_swap_64(dst,expected,desired) __sync_val_compare_and_swap(dst,expected,desired)
#else
#if defined(MA_X86)
#define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc")
#elif defined(MA_X64)
#define ma_atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc")
#else
#error Unsupported architecture. Please submit a feature request.
#endif
static MA_INLINE ma_uint8 ma_atomic_compare_and_swap_8(volatile ma_uint8*dst,ma_uint8 expected,ma_uint8 desired)
{
ma_uint8 Mf;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(Mf) : "a"(expected), "d"(desired) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE ma_uint16 ma_atomic_compare_and_swap_16(volatile ma_uint16*dst,ma_uint16 expected,ma_uint16 desired)
{
ma_uint16 Mf;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(Mf) : "a"(expected), "d"(desired) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE M3 ma_atomic_compare_and_swap_32(volatile M3*dst,M3 expected,M3 desired)
{
M3 Mf;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(Mf) : "a"(expected), "d"(desired) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE M6 ma_atomic_compare_and_swap_64(volatile M6*dst,M6 expected,M6 desired)
{
volatile M6 Mf;
#if defined(MA_X86)
M3 resultEAX;
M3 resultEDX;
__asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc");
Mf=((M6)resultEDX<<32)|resultEAX;
#elif defined(MA_X64)
__asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(Mf) : "a"(expected), "d"(desired) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE ma_uint8 ma_atomic_exchange_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 Mf=0;
(Mv)order;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src));
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE ma_uint16 ma_atomic_exchange_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 Mf=0;
(Mv)order;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src));
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE M3 ma_atomic_exchange_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 Mf;
(Mv)order;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src));
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE M6 ma_atomic_exchange_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 Mf;
(Mv)order;
#if defined(MA_X86)
do {
Mf=*dst;
} while (ma_atomic_compare_and_swap_64(dst,Mf,src) !=Mf);
#elif defined(MA_X64)
__asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src));
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE ma_uint8 ma_atomic_fetch_add_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 Mf;
(Mv)order;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE ma_uint16 ma_atomic_fetch_add_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 Mf;
(Mv)order;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE M3 ma_atomic_fetch_add_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 Mf;
(Mv)order;
#if defined(MA_X86)||defined(MA_X64)
__asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src) : "cc");
#else
#error Unsupported architecture. Please submit a feature request.
#endif
Mr Mf;
}
static MA_INLINE M6 ma_atomic_fetch_add_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
#if defined(MA_X86)
M6 oldValue;
M6 newValue;
(Mv)order;
do {
oldValue=*dst;
newValue=oldValue+src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
Mr oldValue;
#elif defined(MA_X64)
M6 Mf;
(Mv)order;
__asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(Mf) : "a"(src) : "cc");
Mr Mf;
#endif
}
static MA_INLINE ma_uint8 ma_atomic_fetch_sub_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue-src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint16 ma_atomic_fetch_sub_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue-src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M3 ma_atomic_fetch_sub_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue-src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M6 ma_atomic_fetch_sub_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue-src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint8 ma_atomic_fetch_and_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue&src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint16 ma_atomic_fetch_and_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue&src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M3 ma_atomic_fetch_and_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue&src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M6 ma_atomic_fetch_and_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue&src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint8 ma_atomic_fetch_xor_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue ^ src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint16 ma_atomic_fetch_xor_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue ^ src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M3 ma_atomic_fetch_xor_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue ^ src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M6 ma_atomic_fetch_xor_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue ^ src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint8 ma_atomic_fetch_or_explicit_8(volatile ma_uint8*dst,ma_uint8 src,ma_atomic_memory_order order)
{
ma_uint8 oldValue;
ma_uint8 newValue;
do {
oldValue=*dst;
newValue=(ma_uint8)(oldValue|src);
} while (ma_atomic_compare_and_swap_8(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE ma_uint16 ma_atomic_fetch_or_explicit_16(volatile ma_uint16*dst,ma_uint16 src,ma_atomic_memory_order order)
{
ma_uint16 oldValue;
ma_uint16 newValue;
do {
oldValue=*dst;
newValue=(ma_uint16)(oldValue|src);
} while (ma_atomic_compare_and_swap_16(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M3 ma_atomic_fetch_or_explicit_32(volatile M3*dst,M3 src,ma_atomic_memory_order order)
{
M3 oldValue;
M3 newValue;
do {
oldValue=*dst;
newValue=oldValue|src;
} while (ma_atomic_compare_and_swap_32(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
static MA_INLINE M6 ma_atomic_fetch_or_explicit_64(volatile M6*dst,M6 src,ma_atomic_memory_order order)
{
M6 oldValue;
M6 newValue;
do {
oldValue=*dst;
newValue=oldValue|src;
} while (ma_atomic_compare_and_swap_64(dst,oldValue,newValue) !=oldValue);
(Mv)order;
Mr oldValue;
}
#endif
#define ma_atomic_signal_fence(order) ma_atomic_thread_fence(order)
static MA_INLINE ma_uint8 ma_atomic_load_explicit_8(volatile const ma_uint8*ptr,ma_atomic_memory_order order)
{
(Mv)order;
Mr ma_atomic_compare_and_swap_8((ma_uint8*)ptr,0,0);
}
static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16*ptr,ma_atomic_memory_order order)
{
(Mv)order;
Mr ma_atomic_compare_and_swap_16((ma_uint16*)ptr,0,0);
}
static MA_INLINE M3 ma_atomic_load_explicit_32(volatile const M3*ptr,ma_atomic_memory_order order)
{
(Mv)order;
Mr ma_atomic_compare_and_swap_32((M3*)ptr,0,0);
}
static MA_INLINE M6 ma_atomic_load_explicit_64(volatile const M6*ptr,ma_atomic_memory_order order)
{
(Mv)order;
Mr ma_atomic_compare_and_swap_64((M6*)ptr,0,0);
}
#define ma_atomic_store_explicit_8( dst,src,order) (Mv)ma_atomic_exchange_explicit_8 (dst,src,order)
#define ma_atomic_store_explicit_16(dst,src,order) (Mv)ma_atomic_exchange_explicit_16(dst,src,order)
#define ma_atomic_store_explicit_32(dst,src,order) (Mv)ma_atomic_exchange_explicit_32(dst,src,order)
#define ma_atomic_store_explicit_64(dst,src,order) (Mv)ma_atomic_exchange_explicit_64(dst,src,order)
#define ma_atomic_test_and_set_explicit_8( dst,order) ma_atomic_exchange_explicit_8 (dst,1,order)
#define ma_atomic_test_and_set_explicit_16(dst,order) ma_atomic_exchange_explicit_16(dst,1,order)
#define ma_atomic_test_and_set_explicit_32(dst,order) ma_atomic_exchange_explicit_32(dst,1,order)
#define ma_atomic_test_and_set_explicit_64(dst,order) ma_atomic_exchange_explicit_64(dst,1,order)
#define ma_atomic_clear_explicit_8( dst,order) ma_atomic_store_explicit_8 (dst,0,order)
#define ma_atomic_clear_explicit_16(dst,order) ma_atomic_store_explicit_16(dst,0,order)
#define ma_atomic_clear_explicit_32(dst,order) ma_atomic_store_explicit_32(dst,0,order)
#define ma_atomic_clear_explicit_64(dst,order) ma_atomic_store_explicit_64(dst,0,order)
typedef ma_uint8 ma_atomic_flag;
#define ma_atomic_flag_test_and_set_explicit(ptr,order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr,order)
#define ma_atomic_flag_clear_explicit(ptr,order) ma_atomic_clear_explicit_8(ptr,order)
#define ma_atomic_flag_load_explicit(ptr,order) ma_atomic_load_explicit_8(ptr,order)
#endif
#if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE)
#if defined(MA_ATOMIC_HAS_8)
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_8(volatile ma_uint8*dst,ma_uint8*expected,ma_uint8 desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
ma_uint8 expectedValue;
ma_uint8 Mf;
(Mv)successOrder;
(Mv)failureOrder;
expectedValue=ma_atomic_load_explicit_8(expected,ma_atomic_memory_order_seq_cst);
Mf=ma_atomic_compare_and_swap_8(dst,expectedValue,desired);
if (Mf==expectedValue) {
Mr 1;
} else {
ma_atomic_store_explicit_8(expected,Mf,failureOrder);
Mr 0;
}
}
#endif
#if defined(MA_ATOMIC_HAS_16)
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_16(volatile ma_uint16*dst,ma_uint16*expected,ma_uint16 desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
ma_uint16 expectedValue;
ma_uint16 Mf;
(Mv)successOrder;
(Mv)failureOrder;
expectedValue=ma_atomic_load_explicit_16(expected,ma_atomic_memory_order_seq_cst);
Mf=ma_atomic_compare_and_swap_16(dst,expectedValue,desired);
if (Mf==expectedValue) {
Mr 1;
} else {
ma_atomic_store_explicit_16(expected,Mf,failureOrder);
Mr 0;
}
}
#endif
#if defined(MA_ATOMIC_HAS_32)
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_32(volatile M3*dst,M3*expected,M3 desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
M3 expectedValue;
M3 Mf;
(Mv)successOrder;
(Mv)failureOrder;
expectedValue=ma_atomic_load_explicit_32(expected,ma_atomic_memory_order_seq_cst);
Mf=ma_atomic_compare_and_swap_32(dst,expectedValue,desired);
if (Mf==expectedValue) {
Mr 1;
} else {
ma_atomic_store_explicit_32(expected,Mf,failureOrder);
Mr 0;
}
}
#endif
#if defined(MA_ATOMIC_HAS_64)
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_64(volatile M6*dst,volatile M6*expected,M6 desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
M6 expectedValue;
M6 Mf;
(Mv)successOrder;
(Mv)failureOrder;
expectedValue=ma_atomic_load_explicit_64(expected,ma_atomic_memory_order_seq_cst);
Mf=ma_atomic_compare_and_swap_64(dst,expectedValue,desired);
if (Mf==expectedValue) {
Mr 1;
} else {
ma_atomic_store_explicit_64(expected,Mf,failureOrder);
Mr 0;
}
}
#endif
#define ma_atomic_compare_exchange_weak_explicit_8( dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_8 (dst,expected,desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_16(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_16(dst,expected,desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_32(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_32(dst,expected,desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_64(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_64(dst,expected,desired,successOrder,failureOrder)
#endif
#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE)
static MA_INLINE ma_bool32 ma_atomic_is_lock_free_8(volatile Mv*ptr)
{
(Mv)ptr;
Mr 1;
}
static MA_INLINE ma_bool32 ma_atomic_is_lock_free_16(volatile Mv*ptr)
{
(Mv)ptr;
Mr 1;
}
static MA_INLINE ma_bool32 ma_atomic_is_lock_free_32(volatile Mv*ptr)
{
(Mv)ptr;
Mr 1;
}
static MA_INLINE ma_bool32 ma_atomic_is_lock_free_64(volatile Mv*ptr)
{
(Mv)ptr;
#if defined(MA_64BIT)
Mr 1;
#else
#if defined(MA_X86)||defined(MA_X64)
Mr 1;
#else
Mr 0;
#endif
#endif
}
#endif
#if defined(MA_64BIT)
static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile Mv**ptr)
{
Mr ma_atomic_is_lock_free_64((volatile M6*)ptr);
}
static MA_INLINE Mv*ma_atomic_load_explicit_ptr(volatile Mv**ptr,ma_atomic_memory_order order)
{
Mr (Mv*)ma_atomic_load_explicit_64((volatile M6*)ptr,order);
}
static MA_INLINE Mv ma_atomic_store_explicit_ptr(volatile Mv**dst,Mv*src,ma_atomic_memory_order order)
{
ma_atomic_store_explicit_64((volatile M6*)dst,(M6)src,order);
}
static MA_INLINE Mv*ma_atomic_exchange_explicit_ptr(volatile Mv**dst,Mv*src,ma_atomic_memory_order order)
{
Mr (Mv*)ma_atomic_exchange_explicit_64((volatile M6*)dst,(M6)src,order);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile Mv**dst,Mv**expected,Mv*desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
Mr ma_atomic_compare_exchange_strong_explicit_64((volatile M6*)dst,(M6*)expected,(M6)desired,successOrder,failureOrder);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile Mv**dst,Mv**expected,Mv*desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
Mr ma_atomic_compare_exchange_weak_explicit_64((volatile M6*)dst,(M6*)expected,(M6)desired,successOrder,failureOrder);
}
static MA_INLINE Mv*ma_atomic_compare_and_swap_ptr(volatile Mv**dst,Mv*expected,Mv*desired)
{
Mr (Mv*)ma_atomic_compare_and_swap_64((volatile M6*)dst,(M6)expected,(M6)desired);
}
#elif defined(MA_32BIT)
static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile Mv**ptr)
{
Mr ma_atomic_is_lock_free_32((volatile M3*)ptr);
}
static MA_INLINE Mv*ma_atomic_load_explicit_ptr(volatile Mv**ptr,ma_atomic_memory_order order)
{
Mr (Mv*)ma_atomic_load_explicit_32((volatile M3*)ptr,order);
}
static MA_INLINE Mv ma_atomic_store_explicit_ptr(volatile Mv**dst,Mv*src,ma_atomic_memory_order order)
{
ma_atomic_store_explicit_32((volatile M3*)dst,(M3)src,order);
}
static MA_INLINE Mv*ma_atomic_exchange_explicit_ptr(volatile Mv**dst,Mv*src,ma_atomic_memory_order order)
{
Mr (Mv*)ma_atomic_exchange_explicit_32((volatile M3*)dst,(M3)src,order);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_ptr(volatile Mv**dst,Mv**expected,Mv*desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
Mr ma_atomic_compare_exchange_strong_explicit_32((volatile M3*)dst,(M3*)expected,(M3)desired,successOrder,failureOrder);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_ptr(volatile Mv**dst,Mv**expected,Mv*desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
Mr ma_atomic_compare_exchange_weak_explicit_32((volatile M3*)dst,(M3*)expected,(M3)desired,successOrder,failureOrder);
}
static MA_INLINE Mv*ma_atomic_compare_and_swap_ptr(volatile Mv**dst,Mv*expected,Mv*desired)
{
Mr (Mv*)ma_atomic_compare_and_swap_32((volatile M3*)dst,(M3)expected,(M3)desired);
}
#else
#error Unsupported architecture.
#endif
#define ma_atomic_flag_test_and_set(ptr) ma_atomic_flag_test_and_set_explicit(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_flag_clear(ptr) ma_atomic_flag_clear_explicit(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_ptr(dst,src) ma_atomic_store_explicit_ptr((volatile Mv**)dst,(Mv*)src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_ptr(ptr) ma_atomic_load_explicit_ptr((volatile Mv**)ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_ptr(dst,src) ma_atomic_exchange_explicit_ptr((volatile Mv**)dst,(Mv*)src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_ptr(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_ptr((volatile Mv**)dst,(Mv**)expected,(Mv*)desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_ptr(dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_ptr((volatile Mv**)dst,(Mv**)expected,(Mv*)desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_8( ptr) ma_atomic_test_and_set_explicit_8( ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_16(ptr) ma_atomic_test_and_set_explicit_16(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_32(ptr) ma_atomic_test_and_set_explicit_32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_64(ptr) ma_atomic_test_and_set_explicit_64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_8( ptr) ma_atomic_clear_explicit_8( ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_16(ptr) ma_atomic_clear_explicit_16(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_32(ptr) ma_atomic_clear_explicit_32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_64(ptr) ma_atomic_clear_explicit_64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_8( dst,src) ma_atomic_store_explicit_8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_16(dst,src) ma_atomic_store_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_32(dst,src) ma_atomic_store_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_64(dst,src) ma_atomic_store_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_8( ptr) ma_atomic_load_explicit_8( ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_16(ptr) ma_atomic_load_explicit_16(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_32(ptr) ma_atomic_load_explicit_32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_64(ptr) ma_atomic_load_explicit_64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_8( dst,src) ma_atomic_exchange_explicit_8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_16(dst,src) ma_atomic_exchange_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_32(dst,src) ma_atomic_exchange_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_64(dst,src) ma_atomic_exchange_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_8( dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_8( dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_16(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_16(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_32(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_32(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_64(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_64(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_8( dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_8( dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_16( dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_16(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_32( dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_32(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_64( dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_64(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_8( dst,src) ma_atomic_fetch_add_explicit_8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_16(dst,src) ma_atomic_fetch_add_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_32(dst,src) ma_atomic_fetch_add_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_64(dst,src) ma_atomic_fetch_add_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_8( dst,src) ma_atomic_fetch_sub_explicit_8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_16(dst,src) ma_atomic_fetch_sub_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_32(dst,src) ma_atomic_fetch_sub_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_64(dst,src) ma_atomic_fetch_sub_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_8( dst,src) ma_atomic_fetch_or_explicit_8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_16(dst,src) ma_atomic_fetch_or_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_32(dst,src) ma_atomic_fetch_or_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_64(dst,src) ma_atomic_fetch_or_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_8( dst,src) ma_atomic_fetch_xor_explicit_8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_16(dst,src) ma_atomic_fetch_xor_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_32(dst,src) ma_atomic_fetch_xor_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_64(dst,src) ma_atomic_fetch_xor_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_8( dst,src) ma_atomic_fetch_and_explicit_8 (dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_16(dst,src) ma_atomic_fetch_and_explicit_16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_32(dst,src) ma_atomic_fetch_and_explicit_32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_64(dst,src) ma_atomic_fetch_and_explicit_64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_explicit_i8( ptr,order) (ma_int8 )ma_atomic_test_and_set_explicit_8( (ma_uint8*)ptr,order)
#define ma_atomic_test_and_set_explicit_i16(ptr,order) (ma_int16)ma_atomic_test_and_set_explicit_16((ma_uint16*)ptr,order)
#define ma_atomic_test_and_set_explicit_i32(ptr,order) (ma_int32)ma_atomic_test_and_set_explicit_32((M3*)ptr,order)
#define ma_atomic_test_and_set_explicit_i64(ptr,order) (ma_int64)ma_atomic_test_and_set_explicit_64((M6*)ptr,order)
#define ma_atomic_clear_explicit_i8( ptr,order) ma_atomic_clear_explicit_8( (ma_uint8*)ptr,order)
#define ma_atomic_clear_explicit_i16(ptr,order) ma_atomic_clear_explicit_16((ma_uint16*)ptr,order)
#define ma_atomic_clear_explicit_i32(ptr,order) ma_atomic_clear_explicit_32((M3*)ptr,order)
#define ma_atomic_clear_explicit_i64(ptr,order) ma_atomic_clear_explicit_64((M6*)ptr,order)
#define ma_atomic_store_explicit_i8( dst,src,order) ma_atomic_store_explicit_8( (ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_store_explicit_i16(dst,src,order) ma_atomic_store_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_store_explicit_i32(dst,src,order) ma_atomic_store_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_store_explicit_i64(dst,src,order) ma_atomic_store_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_load_explicit_i8( ptr,order) (ma_int8 )ma_atomic_load_explicit_8( (ma_uint8*)ptr,order)
#define ma_atomic_load_explicit_i16(ptr,order) (ma_int16)ma_atomic_load_explicit_16((ma_uint16*)ptr,order)
#define ma_atomic_load_explicit_i32(ptr,order) (ma_int32)ma_atomic_load_explicit_32((M3*)ptr,order)
#define ma_atomic_load_explicit_i64(ptr,order) (ma_int64)ma_atomic_load_explicit_64((M6*)ptr,order)
#define ma_atomic_exchange_explicit_i8( dst,src,order) (ma_int8 )ma_atomic_exchange_explicit_8 ((ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_exchange_explicit_i16(dst,src,order) (ma_int16)ma_atomic_exchange_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_exchange_explicit_i32(dst,src,order) (ma_int32)ma_atomic_exchange_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_exchange_explicit_i64(dst,src,order) (ma_int64)ma_atomic_exchange_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_compare_exchange_strong_explicit_i8( dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_8( (ma_uint8*)dst,(ma_uint8*)expected,(ma_uint8 )desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_strong_explicit_i16(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_16((ma_uint16*)dst,(ma_uint16*)expected,(ma_uint16)desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_strong_explicit_i32(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_32((M3*)dst,(M3*)expected,(M3)desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_strong_explicit_i64(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_strong_explicit_64((M6*)dst,(M6*)expected,(M6)desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_i8( dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_weak_explicit_8( (ma_uint8*)dst,(ma_uint8*)expected,(ma_uint8 )desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_i16(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_weak_explicit_16((ma_uint16*)dst,(ma_uint16*)expected,(ma_uint16)desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_i32(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_weak_explicit_32((M3*)dst,(M3*)expected,(M3)desired,successOrder,failureOrder)
#define ma_atomic_compare_exchange_weak_explicit_i64(dst,expected,desired,successOrder,failureOrder) ma_atomic_compare_exchange_weak_explicit_64((M6*)dst,(M6*)expected,(M6)desired,successOrder,failureOrder)
#define ma_atomic_fetch_add_explicit_i8( dst,src,order) (ma_int8 )ma_atomic_fetch_add_explicit_8( (ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_fetch_add_explicit_i16(dst,src,order) (ma_int16)ma_atomic_fetch_add_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_fetch_add_explicit_i32(dst,src,order) (ma_int32)ma_atomic_fetch_add_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_fetch_add_explicit_i64(dst,src,order) (ma_int64)ma_atomic_fetch_add_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_fetch_sub_explicit_i8( dst,src,order) (ma_int8 )ma_atomic_fetch_sub_explicit_8( (ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_fetch_sub_explicit_i16(dst,src,order) (ma_int16)ma_atomic_fetch_sub_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_fetch_sub_explicit_i32(dst,src,order) (ma_int32)ma_atomic_fetch_sub_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_fetch_sub_explicit_i64(dst,src,order) (ma_int64)ma_atomic_fetch_sub_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_fetch_or_explicit_i8( dst,src,order) (ma_int8 )ma_atomic_fetch_or_explicit_8( (ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_fetch_or_explicit_i16(dst,src,order) (ma_int16)ma_atomic_fetch_or_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_fetch_or_explicit_i32(dst,src,order) (ma_int32)ma_atomic_fetch_or_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_fetch_or_explicit_i64(dst,src,order) (ma_int64)ma_atomic_fetch_or_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_fetch_xor_explicit_i8( dst,src,order) (ma_int8 )ma_atomic_fetch_xor_explicit_8( (ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_fetch_xor_explicit_i16(dst,src,order) (ma_int16)ma_atomic_fetch_xor_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_fetch_xor_explicit_i32(dst,src,order) (ma_int32)ma_atomic_fetch_xor_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_fetch_xor_explicit_i64(dst,src,order) (ma_int64)ma_atomic_fetch_xor_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_fetch_and_explicit_i8( dst,src,order) (ma_int8 )ma_atomic_fetch_and_explicit_8( (ma_uint8*)dst,(ma_uint8 )src,order)
#define ma_atomic_fetch_and_explicit_i16(dst,src,order) (ma_int16)ma_atomic_fetch_and_explicit_16((ma_uint16*)dst,(ma_uint16)src,order)
#define ma_atomic_fetch_and_explicit_i32(dst,src,order) (ma_int32)ma_atomic_fetch_and_explicit_32((M3*)dst,(M3)src,order)
#define ma_atomic_fetch_and_explicit_i64(dst,src,order) (ma_int64)ma_atomic_fetch_and_explicit_64((M6*)dst,(M6)src,order)
#define ma_atomic_test_and_set_i8( ptr) ma_atomic_test_and_set_explicit_i8( ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_i16(ptr) ma_atomic_test_and_set_explicit_i16(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_i32(ptr) ma_atomic_test_and_set_explicit_i32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_test_and_set_i64(ptr) ma_atomic_test_and_set_explicit_i64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_i8( ptr) ma_atomic_clear_explicit_i8( ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_i16(ptr) ma_atomic_clear_explicit_i16(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_i32(ptr) ma_atomic_clear_explicit_i32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_i64(ptr) ma_atomic_clear_explicit_i64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_i8( dst,src) ma_atomic_store_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_i16(dst,src) ma_atomic_store_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_i32(dst,src) ma_atomic_store_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_i64(dst,src) ma_atomic_store_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_i8( ptr) ma_atomic_load_explicit_i8( ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_i16(ptr) ma_atomic_load_explicit_i16(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_i32(ptr) ma_atomic_load_explicit_i32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_i64(ptr) ma_atomic_load_explicit_i64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_i8( dst,src) ma_atomic_exchange_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_i16(dst,src) ma_atomic_exchange_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_i32(dst,src) ma_atomic_exchange_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_i64(dst,src) ma_atomic_exchange_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_i8( dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_i8( dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_i16(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_i16(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_i32(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_i32(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_i64(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_i64(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_i8( dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_i8( dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_i16(dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_i16(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_i32(dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_i32(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_i64(dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_i64(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_i8( dst,src) ma_atomic_fetch_add_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_i16(dst,src) ma_atomic_fetch_add_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_i32(dst,src) ma_atomic_fetch_add_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_i64(dst,src) ma_atomic_fetch_add_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_i8( dst,src) ma_atomic_fetch_sub_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_i16(dst,src) ma_atomic_fetch_sub_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_i32(dst,src) ma_atomic_fetch_sub_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_i64(dst,src) ma_atomic_fetch_sub_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_i8( dst,src) ma_atomic_fetch_or_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_i16(dst,src) ma_atomic_fetch_or_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_i32(dst,src) ma_atomic_fetch_or_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_i64(dst,src) ma_atomic_fetch_or_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_i8( dst,src) ma_atomic_fetch_xor_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_i16(dst,src) ma_atomic_fetch_xor_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_i32(dst,src) ma_atomic_fetch_xor_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_i64(dst,src) ma_atomic_fetch_xor_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_i8( dst,src) ma_atomic_fetch_and_explicit_i8( dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_i16(dst,src) ma_atomic_fetch_and_explicit_i16(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_i32(dst,src) ma_atomic_fetch_and_explicit_i32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_i64(dst,src) ma_atomic_fetch_and_explicit_i64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_and_swap_i8( dst,expected,dedsired) (ma_int8 )ma_atomic_compare_and_swap_8( (ma_uint8*)dst,(ma_uint8 )expected,(ma_uint8 )dedsired)
#define ma_atomic_compare_and_swap_i16(dst,expected,dedsired) (ma_int16)ma_atomic_compare_and_swap_16((ma_uint16*)dst,(ma_uint16)expected,(ma_uint16)dedsired)
#define ma_atomic_compare_and_swap_i32(dst,expected,dedsired) (ma_int32)ma_atomic_compare_and_swap_32((M3*)dst,(M3)expected,(M3)dedsired)
#define ma_atomic_compare_and_swap_i64(dst,expected,dedsired) (ma_int64)ma_atomic_compare_and_swap_64((M6*)dst,(M6)expected,(M6)dedsired)
typedef union
{
M3 i;
float f;
} ma_atomic_if32;
typedef union
{
M6 i;
double f;
} ma_atomic_if64;
#define ma_atomic_clear_explicit_f32(ptr,order) ma_atomic_clear_explicit_32((M3*)ptr,order)
#define ma_atomic_clear_explicit_f64(ptr,order) ma_atomic_clear_explicit_64((M6*)ptr,order)
static MA_INLINE Mv ma_atomic_store_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 x;
x.f=src;
ma_atomic_store_explicit_32((volatile M3*)dst,x.i,order);
}
static MA_INLINE Mv ma_atomic_store_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 x;
x.f=src;
ma_atomic_store_explicit_64((volatile M6*)dst,x.i,order);
}
static MA_INLINE float ma_atomic_load_explicit_f32(volatile const float*ptr,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
r.i=ma_atomic_load_explicit_32((volatile const M3*)ptr,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_load_explicit_f64(volatile const double*ptr,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
r.i=ma_atomic_load_explicit_64((volatile const M6*)ptr,order);
Mr r.f;
}
static MA_INLINE float ma_atomic_exchange_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
ma_atomic_if32 x;
x.f=src;
r.i=ma_atomic_exchange_explicit_32((volatile M3*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_exchange_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
ma_atomic_if64 x;
x.f=src;
r.i=ma_atomic_exchange_explicit_64((volatile M6*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f32(volatile float*dst,float*expected,float desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
ma_atomic_if32 d;
d.f=desired;
Mr ma_atomic_compare_exchange_strong_explicit_32((volatile M3*)dst,(M3*)expected,d.i,successOrder,failureOrder);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_strong_explicit_f64(volatile double*dst,double*expected,double desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
ma_atomic_if64 d;
d.f=desired;
Mr ma_atomic_compare_exchange_strong_explicit_64((volatile M6*)dst,(M6*)expected,d.i,successOrder,failureOrder);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f32(volatile float*dst,float*expected,float desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
ma_atomic_if32 d;
d.f=desired;
Mr ma_atomic_compare_exchange_weak_explicit_32((volatile M3*)dst,(M3*)expected,d.i,successOrder,failureOrder);
}
static MA_INLINE ma_bool32 ma_atomic_compare_exchange_weak_explicit_f64(volatile double*dst,double*expected,double desired,ma_atomic_memory_order successOrder,ma_atomic_memory_order failureOrder)
{
ma_atomic_if64 d;
d.f=desired;
Mr ma_atomic_compare_exchange_weak_explicit_64((volatile M6*)dst,(M6*)expected,d.i,successOrder,failureOrder);
}
static MA_INLINE float ma_atomic_fetch_add_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
ma_atomic_if32 x;
x.f=src;
r.i=ma_atomic_fetch_add_explicit_32((volatile M3*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_fetch_add_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
ma_atomic_if64 x;
x.f=src;
r.i=ma_atomic_fetch_add_explicit_64((volatile M6*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE float ma_atomic_fetch_sub_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
ma_atomic_if32 x;
x.f=src;
r.i=ma_atomic_fetch_sub_explicit_32((volatile M3*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_fetch_sub_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
ma_atomic_if64 x;
x.f=src;
r.i=ma_atomic_fetch_sub_explicit_64((volatile M6*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE float ma_atomic_fetch_or_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
ma_atomic_if32 x;
x.f=src;
r.i=ma_atomic_fetch_or_explicit_32((volatile M3*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_fetch_or_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
ma_atomic_if64 x;
x.f=src;
r.i=ma_atomic_fetch_or_explicit_64((volatile M6*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE float ma_atomic_fetch_xor_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
ma_atomic_if32 x;
x.f=src;
r.i=ma_atomic_fetch_xor_explicit_32((volatile M3*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_fetch_xor_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
ma_atomic_if64 x;
x.f=src;
r.i=ma_atomic_fetch_xor_explicit_64((volatile M6*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE float ma_atomic_fetch_and_explicit_f32(volatile float*dst,float src,ma_atomic_memory_order order)
{
ma_atomic_if32 r;
ma_atomic_if32 x;
x.f=src;
r.i=ma_atomic_fetch_and_explicit_32((volatile M3*)dst,x.i,order);
Mr r.f;
}
static MA_INLINE double ma_atomic_fetch_and_explicit_f64(volatile double*dst,double src,ma_atomic_memory_order order)
{
ma_atomic_if64 r;
ma_atomic_if64 x;
x.f=src;
r.i=ma_atomic_fetch_and_explicit_64((volatile M6*)dst,x.i,order);
Mr r.f;
}
#define ma_atomic_clear_f32(ptr) (float )ma_atomic_clear_explicit_f32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_clear_f64(ptr) (double)ma_atomic_clear_explicit_f64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_f32(dst,src) ma_atomic_store_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_store_f64(dst,src) ma_atomic_store_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_f32(ptr) (float )ma_atomic_load_explicit_f32(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_load_f64(ptr) (double)ma_atomic_load_explicit_f64(ptr,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_f32(dst,src) (float )ma_atomic_exchange_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_exchange_f64(dst,src) (double)ma_atomic_exchange_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_f32(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_f32(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_strong_f64(dst,expected,desired) ma_atomic_compare_exchange_strong_explicit_f64(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_f32(dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_f32(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_compare_exchange_weak_f64(dst,expected,desired) ma_atomic_compare_exchange_weak_explicit_f64(dst,expected,desired,ma_atomic_memory_order_seq_cst,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_f32(dst,src) ma_atomic_fetch_add_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_add_f64(dst,src) ma_atomic_fetch_add_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_f32(dst,src) ma_atomic_fetch_sub_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_sub_f64(dst,src) ma_atomic_fetch_sub_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_f32(dst,src) ma_atomic_fetch_or_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_or_f64(dst,src) ma_atomic_fetch_or_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_f32(dst,src) ma_atomic_fetch_xor_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_xor_f64(dst,src) ma_atomic_fetch_xor_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_f32(dst,src) ma_atomic_fetch_and_explicit_f32(dst,src,ma_atomic_memory_order_seq_cst)
#define ma_atomic_fetch_and_f64(dst,src) ma_atomic_fetch_and_explicit_f64(dst,src,ma_atomic_memory_order_seq_cst)
static MA_INLINE float ma_atomic_compare_and_swap_f32(volatile float*dst,float expected,float desired)
{
ma_atomic_if32 r;
ma_atomic_if32 e,d;
e.f=expected;
d.f=desired;
r.i=ma_atomic_compare_and_swap_32((volatile M3*)dst,e.i,d.i);
Mr r.f;
}
static MA_INLINE double ma_atomic_compare_and_swap_f64(volatile double*dst,double expected,double desired)
{
ma_atomic_if64 r;
ma_atomic_if64 e,d;
e.f=expected;
d.f=desired;
r.i=ma_atomic_compare_and_swap_64((volatile M6*)dst,e.i,d.i);
Mr r.f;
}
typedef ma_atomic_flag ma_atomic_spinlock;
static MA_INLINE Mv ma_atomic_spinlock_lock(volatile ma_atomic_spinlock*pSpinlock)
{
for (;;) {
if (ma_atomic_flag_test_and_set_explicit(pSpinlock,ma_atomic_memory_order_acquire)==0) {
break;
}
while (ma_atomic_flag_load_explicit(pSpinlock,ma_atomic_memory_order_relaxed)==1) {
}
}
}
static MA_INLINE Mv ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock*pSpinlock)
{
ma_atomic_flag_clear_explicit(pSpinlock,ma_atomic_memory_order_release);
}
#if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=6)))
#pragma GCC diagnostic pop
#endif
#if defined(__cplusplus)
}
#endif
#endif
#define MA_ATOMIC_SAFE_TYPE_IMPL(c89TypeExtension,type)\
static MA_INLINE ma_##type ma_atomic_##type##_get(ma_atomic_##type*x)\
{\
Mr (ma_##type)ma_atomic_load_##c89TypeExtension(&x->value);\
}\
static MA_INLINE Mv ma_atomic_##type##_set(ma_atomic_##type*x,ma_##type value)\
{\
ma_atomic_store_##c89TypeExtension(&x->value,value);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_exchange(ma_atomic_##type*x,ma_##type value)\
{\
Mr (ma_##type)ma_atomic_exchange_##c89TypeExtension(&x->value,value);\
}\
static MA_INLINE ma_bool32 ma_atomic_##type##_compare_exchange(ma_atomic_##type*x,ma_##type*expected,ma_##type desired)\
{\
Mr ma_atomic_compare_exchange_weak_##c89TypeExtension(&x->value,expected,desired);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_fetch_add(ma_atomic_##type*x,ma_##type y)\
{\
Mr (ma_##type)ma_atomic_fetch_add_##c89TypeExtension(&x->value,y);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_fetch_sub(ma_atomic_##type*x,ma_##type y)\
{\
Mr (ma_##type)ma_atomic_fetch_sub_##c89TypeExtension(&x->value,y);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_fetch_or(ma_atomic_##type*x,ma_##type y)\
{\
Mr (ma_##type)ma_atomic_fetch_or_##c89TypeExtension(&x->value,y);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_fetch_xor(ma_atomic_##type*x,ma_##type y)\
{\
Mr (ma_##type)ma_atomic_fetch_xor_##c89TypeExtension(&x->value,y);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_fetch_and(ma_atomic_##type*x,ma_##type y)\
{\
Mr (ma_##type)ma_atomic_fetch_and_##c89TypeExtension(&x->value,y);\
}\
static MA_INLINE ma_##type ma_atomic_##type##_compare_and_swap(ma_atomic_##type*x,ma_##type expected,ma_##type desired)\
{\
Mr (ma_##type)ma_atomic_compare_and_swap_##c89TypeExtension(&x->value,expected,desired);\
}
#define MA_ATOMIC_SAFE_TYPE_IMPL_PTR(type)\
static MA_INLINE ma_##type*ma_atomic_ptr_##type##_get(ma_atomic_ptr_##type*x)\
{\
Mr ma_atomic_load_ptr((Mv**)&x->value);\
}\
static MA_INLINE Mv ma_atomic_ptr_##type##_set(ma_atomic_ptr_##type*x,ma_##type*value)\
{\
ma_atomic_store_ptr((Mv**)&x->value,(Mv*)value);\
}\
static MA_INLINE ma_##type*ma_atomic_ptr_##type##_exchange(ma_atomic_ptr_##type*x,ma_##type*value)\
{\
Mr ma_atomic_exchange_ptr((Mv**)&x->value,(Mv*)value);\
}\
static MA_INLINE ma_bool32 ma_atomic_ptr_##type##_compare_exchange(ma_atomic_ptr_##type*x,ma_##type**expected,ma_##type*desired)\
{\
Mr ma_atomic_compare_exchange_weak_ptr((Mv**)&x->value,(Mv*)expected,(Mv*)desired);\
}\
static MA_INLINE ma_##type*ma_atomic_ptr_##type##_compare_and_swap(ma_atomic_ptr_##type*x,ma_##type*expected,ma_##type*desired)\
{\
Mr (ma_##type*)ma_atomic_compare_and_swap_ptr((Mv**)&x->value,(Mv*)expected,(Mv*)desired);\
}
MA_ATOMIC_SAFE_TYPE_IMPL(32,uint32)
MA_ATOMIC_SAFE_TYPE_IMPL(i32,int32)
MA_ATOMIC_SAFE_TYPE_IMPL(64,uint64)
MA_ATOMIC_SAFE_TYPE_IMPL(f32,float)
MA_ATOMIC_SAFE_TYPE_IMPL(32,bool32)
#if !defined(MA_NO_DEVICE_IO)
MA_ATOMIC_SAFE_TYPE_IMPL(i32,device_state)
#endif
MA_API M6 ma_calculate_frame_count_after_resampling(M3 sampleRateOut,M3 sampleRateIn,M6 frameCountIn)
{
M6 outputFrameCount;
M6 preliminaryInputFrameCountFromFrac;
M6 preliminaryInputFrameCount;
if (sampleRateIn==0||sampleRateOut==0||frameCountIn==0) {
Mr 0;
}
if (sampleRateOut==sampleRateIn) {
Mr frameCountIn;
}
outputFrameCount=(frameCountIn*sampleRateOut) / sampleRateIn;
preliminaryInputFrameCountFromFrac=(outputFrameCount*(sampleRateIn / sampleRateOut)) / sampleRateOut;
preliminaryInputFrameCount=(outputFrameCount*(sampleRateIn % sampleRateOut))+preliminaryInputFrameCountFromFrac;
if (preliminaryInputFrameCount<=frameCountIn) {
outputFrameCount+=1;
}
Mr outputFrameCount;
}
#ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE
#define MA_DATA_CONVERTER_STACK_BUFFER_SIZE 4096
#endif
#if defined(MA_WIN32)
static Me ma_result_from_GetLastError(DWORD error)
{
switch (error)
{
case ERROR_SUCCESS:Mr Ms;
case ERROR_PATH_NOT_FOUND:Mr MA_DOES_NOT_EXIST;
case ERROR_TOO_MANY_OPEN_FILES:Mr MA_TOO_MANY_OPEN_FILES;
case ERROR_NOT_ENOUGH_MEMORY:Mr MA_OUT_OF_MEMORY;
case ERROR_DISK_FULL:Mr MA_NO_SPACE;
case ERROR_HANDLE_EOF:Mr MA_AT_END;
case ERROR_NEGATIVE_SEEK:Mr MA_BAD_SEEK;
case ERROR_INVALID_PARAMETER:Mr MA_INVALID_ARGS;
case ERROR_ACCESS_DENIED:Mr MA_ACCESS_DENIED;
case ERROR_SEM_TIMEOUT:Mr MA_TIMEOUT;
case ERROR_FILE_NOT_FOUND:Mr MA_DOES_NOT_EXIST;
default:break;
}
Mr MA_ERROR;
}
#endif
static MA_INLINE Me ma_spinlock_lock_ex(volatile ma_spinlock*pSpinlock,ma_bool32 yield)
{
if (pSpinlock==NULL) {
Mr MA_INVALID_ARGS;
}
for (;;) {
if (ma_atomic_exchange_explicit_32(pSpinlock,1,ma_atomic_memory_order_acquire)==0) {
break;
}
while (ma_atomic_load_explicit_32(pSpinlock,ma_atomic_memory_order_relaxed)==1) {
if (yield) {
ma_yield();
}
}
}
Mr Ms;
}
MA_API Me ma_spinlock_lock(volatile ma_spinlock*pSpinlock)
{
Mr ma_spinlock_lock_ex(pSpinlock,MA_TRUE);
}
MA_API Me ma_spinlock_lock_noyield(volatile ma_spinlock*pSpinlock)
{
Mr ma_spinlock_lock_ex(pSpinlock,MA_FALSE);
}
MA_API Me ma_spinlock_unlock(volatile ma_spinlock*pSpinlock)
{
if (pSpinlock==NULL) {
Mr MA_INVALID_ARGS;
}
ma_atomic_store_explicit_32(pSpinlock,0,ma_atomic_memory_order_release);
Mr Ms;
}
#ifndef MA_NO_THREADING
#if defined(MA_POSIX)
#define MA_THREADCALL
typedef Mv*ma_thread_result;
#elif defined(MA_WIN32)
#define MA_THREADCALL WINAPI
typedef unsigned long ma_thread_result;
#endif
typedef ma_thread_result (MA_THREADCALL*ma_thread_entry_proc)(Mv*pData);
#ifdef MA_POSIX
static Me ma_thread_create__posix(ma_thread*pThread,ma_thread_priority priority,size_t stackSize,ma_thread_entry_proc entryProc,Mv*pData)
{
int Mf;
pthread_attr_t*pAttr=NULL;
#if !defined(__EMSCRIPTEN__)&&!defined(__3DS__)
pthread_attr_t attr;
if (pthread_attr_init(&attr)==0) {
int scheduler=-1;
pAttr=&attr;
#if !defined(MA_BEOS)
{
if (priority==ma_thread_priority_idle) {
#ifdef SCHED_IDLE
if (pthread_attr_setschedpolicy(&attr,SCHED_IDLE)==0) {
 scheduler=SCHED_IDLE;
}
#endif
} else if (priority==ma_thread_priority_realtime) {
#ifdef SCHED_FIFO
if (pthread_attr_setschedpolicy(&attr,SCHED_FIFO)==0) {
 scheduler=SCHED_FIFO;
}
#endif
#ifdef MA_LINUX
} else {
scheduler=sched_getscheduler(0);
#endif
}
}
#endif
if (stackSize>0) {
pthread_attr_setstacksize(&attr,stackSize);
}
if (scheduler !=-1) {
int priorityMin=sched_get_priority_min(scheduler);
int priorityMax=sched_get_priority_max(scheduler);
int priorityStep=(priorityMax-priorityMin) / 7;
struct sched_param sched;
if (pthread_attr_getschedparam(&attr,&sched)==0) {
if (priority==ma_thread_priority_idle) {
 sched.sched_priority=priorityMin;
} else if (priority==ma_thread_priority_realtime) {
 #if defined(MA_PTHREAD_REALTIME_THREAD_PRIORITY)
 {
 sched.sched_priority=MA_PTHREAD_REALTIME_THREAD_PRIORITY;
 }
 #else
 {
 sched.sched_priority=priorityMax;
 }
 #endif
} else {
 sched.sched_priority+=((int)priority+5)*priorityStep;
}
if (sched.sched_priority<priorityMin) {
 sched.sched_priority=priorityMin;
}
if (sched.sched_priority>priorityMax) {
 sched.sched_priority=priorityMax;
}
if (pthread_attr_setschedparam(&attr,&sched)==0) {
 #if !defined(MA_ANDROID)||(defined(__ANDROID_API__)&&__ANDROID_API__>=28)
 {
 pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);
 }
 #endif
}
}
}
}
#else
(Mv)priority;
(Mv)stackSize;
#endif
Mf=pthread_create((pthread_t*)pThread,pAttr,entryProc,pData);
if (pAttr !=NULL) {
pthread_attr_destroy(pAttr);
}
if (Mf !=0) {
Mr ma_result_from_errno(Mf);
}
Mr Ms;
}
static Mv ma_thread_wait__posix(ma_thread*pThread)
{
pthread_join((pthread_t)*pThread,NULL);
}
static Me ma_mutex_init__posix(ma_mutex*pMutex)
{
int Mf;
if (pMutex==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pMutex);
Mf=pthread_mutex_init((pthread_mutex_t*)pMutex,NULL);
if (Mf !=0) {
Mr ma_result_from_errno(Mf);
}
Mr Ms;
}
static Mv ma_mutex_uninit__posix(ma_mutex*pMutex)
{
pthread_mutex_destroy((pthread_mutex_t*)pMutex);
}
static Mv ma_mutex_lock__posix(ma_mutex*pMutex)
{
pthread_mutex_lock((pthread_mutex_t*)pMutex);
}
static Mv ma_mutex_unlock__posix(ma_mutex*pMutex)
{
pthread_mutex_unlock((pthread_mutex_t*)pMutex);
}
static Me ma_event_init__posix(ma_event*pEvent)
{
int Mf;
Mf=pthread_mutex_init((pthread_mutex_t*)&pEvent->lock,NULL);
if (Mf !=0) {
Mr ma_result_from_errno(Mf);
}
Mf=pthread_cond_init((pthread_cond_t*)&pEvent->cond,NULL);
if (Mf !=0) {
pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
Mr ma_result_from_errno(Mf);
}
pEvent->value=0;
Mr Ms;
}
static Mv ma_event_uninit__posix(ma_event*pEvent)
{
pthread_cond_destroy((pthread_cond_t*)&pEvent->cond);
pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
}
static Me ma_event_wait__posix(ma_event*pEvent)
{
pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
{
while (pEvent->value==0) {
pthread_cond_wait((pthread_cond_t*)&pEvent->cond,(pthread_mutex_t*)&pEvent->lock);
}
pEvent->value=0;
}
pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
Mr Ms;
}
static Me ma_event_signal__posix(ma_event*pEvent)
{
pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
{
pEvent->value=1;
pthread_cond_signal((pthread_cond_t*)&pEvent->cond);
}
pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
Mr Ms;
}
static Me ma_semaphore_init__posix(int initialValue,ma_semaphore*pSemaphore)
{
int Mf;
if (pSemaphore==NULL) {
Mr MA_INVALID_ARGS;
}
pSemaphore->value=initialValue;
Mf=pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock,NULL);
if (Mf !=0) {
Mr ma_result_from_errno(Mf);
}
Mf=pthread_cond_init((pthread_cond_t*)&pSemaphore->cond,NULL);
if (Mf !=0) {
pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
Mr ma_result_from_errno(Mf);
}
Mr Ms;
}
static Mv ma_semaphore_uninit__posix(ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
Mr;
}
pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond);
pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
}
static Me ma_semaphore_wait__posix(ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
Mr MA_INVALID_ARGS;
}
pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
{
while (pSemaphore->value==0) {
pthread_cond_wait((pthread_cond_t*)&pSemaphore->cond,(pthread_mutex_t*)&pSemaphore->lock);
}
pSemaphore->value-=1;
}
pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
Mr Ms;
}
static Me ma_semaphore_release__posix(ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
Mr MA_INVALID_ARGS;
}
pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
{
pSemaphore->value+=1;
pthread_cond_signal((pthread_cond_t*)&pSemaphore->cond);
}
pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
Mr Ms;
}
#elif defined(MA_WIN32)
static int ma_thread_priority_to_win32(ma_thread_priority priority)
{
switch (priority) {
case ma_thread_priority_idle:Mr THREAD_PRIORITY_IDLE;
case ma_thread_priority_lowest:Mr THREAD_PRIORITY_LOWEST;
case ma_thread_priority_low:Mr THREAD_PRIORITY_BELOW_NORMAL;
case ma_thread_priority_normal:Mr THREAD_PRIORITY_NORMAL;
case ma_thread_priority_high:Mr THREAD_PRIORITY_ABOVE_NORMAL;
case ma_thread_priority_highest:Mr THREAD_PRIORITY_HIGHEST;
case ma_thread_priority_realtime:Mr THREAD_PRIORITY_TIME_CRITICAL;
default:Mr THREAD_PRIORITY_NORMAL;
}
}
static Me ma_thread_create__win32(ma_thread*pThread,ma_thread_priority priority,size_t stackSize,ma_thread_entry_proc entryProc,Mv*pData)
{
DWORD threadID;
*pThread=CreateThread(NULL,stackSize,entryProc,pData,0,&threadID);
if (*pThread==NULL) {
Mr ma_result_from_GetLastError(GetLastError());
}
SetThreadPriority((HANDLE)*pThread,ma_thread_priority_to_win32(priority));
Mr Ms;
}
static Mv ma_thread_wait__win32(ma_thread*pThread)
{
WaitForSingleObject((HANDLE)*pThread,INFINITE);
CloseHandle((HANDLE)*pThread);
}
static Me ma_mutex_init__win32(ma_mutex*pMutex)
{
*pMutex=CreateEventA(NULL,FALSE,TRUE,NULL);
if (*pMutex==NULL) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Mv ma_mutex_uninit__win32(ma_mutex*pMutex)
{
CloseHandle((HANDLE)*pMutex);
}
static Mv ma_mutex_lock__win32(ma_mutex*pMutex)
{
WaitForSingleObject((HANDLE)*pMutex,INFINITE);
}
static Mv ma_mutex_unlock__win32(ma_mutex*pMutex)
{
SetEvent((HANDLE)*pMutex);
}
static Me ma_event_init__win32(ma_event*pEvent)
{
*pEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
if (*pEvent==NULL) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Mv ma_event_uninit__win32(ma_event*pEvent)
{
CloseHandle((HANDLE)*pEvent);
}
static Me ma_event_wait__win32(ma_event*pEvent)
{
DWORD Mf=WaitForSingleObject((HANDLE)*pEvent,INFINITE);
if (Mf==WAIT_OBJECT_0) {
Mr Ms;
}
if (Mf==WAIT_TIMEOUT) {
Mr MA_TIMEOUT;
}
Mr ma_result_from_GetLastError(GetLastError());
}
static Me ma_event_signal__win32(ma_event*pEvent)
{
BOOL Mf=SetEvent((HANDLE)*pEvent);
if (Mf==0) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Me ma_semaphore_init__win32(int initialValue,ma_semaphore*pSemaphore)
{
*pSemaphore=CreateSemaphoreW(NULL,(LONG)initialValue,LONG_MAX,NULL);
if (*pSemaphore==NULL) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Mv ma_semaphore_uninit__win32(ma_semaphore*pSemaphore)
{
CloseHandle((HANDLE)*pSemaphore);
}
static Me ma_semaphore_wait__win32(ma_semaphore*pSemaphore)
{
DWORD Mf=WaitForSingleObject((HANDLE)*pSemaphore,INFINITE);
if (Mf==WAIT_OBJECT_0) {
Mr Ms;
}
if (Mf==WAIT_TIMEOUT) {
Mr MA_TIMEOUT;
}
Mr ma_result_from_GetLastError(GetLastError());
}
static Me ma_semaphore_release__win32(ma_semaphore*pSemaphore)
{
BOOL Mf=ReleaseSemaphore((HANDLE)*pSemaphore,1,NULL);
if (Mf==0) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
#endif
typedef struct
{
ma_thread_entry_proc entryProc;
Mv*pData;
ma_allocation_callbacks allocationCallbacks;
} ma_thread_proxy_data;
static ma_thread_result MA_THREADCALL ma_thread_entry_proxy(Mv*pData)
{
ma_thread_proxy_data*pProxyData=(ma_thread_proxy_data*)pData;
ma_thread_entry_proc entryProc;
Mv*pEntryProcData;
ma_thread_result Mf;
#if defined(MA_ON_THREAD_ENTRY)
MA_ON_THREAD_ENTRY
#endif
entryProc=pProxyData->entryProc;
pEntryProcData=pProxyData->pData;
ma_free(pProxyData,&pProxyData->allocationCallbacks);
Mf=entryProc(pEntryProcData);
#if defined(MA_ON_THREAD_EXIT)
MA_ON_THREAD_EXIT
#endif
Mr Mf;
}
static Me ma_thread_create(ma_thread*pThread,ma_thread_priority priority,size_t stackSize,ma_thread_entry_proc entryProc,Mv*pData,const ma_allocation_callbacks*pAllocationCallbacks)
{
Me Mf;
ma_thread_proxy_data*pProxyData;
if (pThread==NULL||entryProc==NULL) {
Mr MA_INVALID_ARGS;
}
pProxyData=(ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData),pAllocationCallbacks);
if (pProxyData==NULL) {
Mr MA_OUT_OF_MEMORY;
}
#if defined(MA_THREAD_DEFAULT_STACK_SIZE)
if (stackSize==0) {
stackSize=MA_THREAD_DEFAULT_STACK_SIZE;
}
#endif
pProxyData->entryProc=entryProc;
pProxyData->pData=pData;
ma_allocation_callbacks_init_copy(&pProxyData->allocationCallbacks,pAllocationCallbacks);
#if defined(MA_POSIX)
Mf=ma_thread_create__posix(pThread,priority,stackSize,ma_thread_entry_proxy,pProxyData);
#elif defined(MA_WIN32)
Mf=ma_thread_create__win32(pThread,priority,stackSize,ma_thread_entry_proxy,pProxyData);
#endif
if (Mf !=Ms) {
ma_free(pProxyData,pAllocationCallbacks);
Mr Mf;
}
Mr Ms;
}
static Mv ma_thread_wait(ma_thread*pThread)
{
if (pThread==NULL) {
Mr;
}
#if defined(MA_POSIX)
ma_thread_wait__posix(pThread);
#elif defined(MA_WIN32)
ma_thread_wait__win32(pThread);
#endif
}
MA_API Me ma_mutex_init(ma_mutex*pMutex)
{
if (pMutex==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_mutex_init__posix(pMutex);
#elif defined(MA_WIN32)
Mr ma_mutex_init__win32(pMutex);
#endif
}
MA_API Mv ma_mutex_uninit(ma_mutex*pMutex)
{
if (pMutex==NULL) {
Mr;
}
#if defined(MA_POSIX)
ma_mutex_uninit__posix(pMutex);
#elif defined(MA_WIN32)
ma_mutex_uninit__win32(pMutex);
#endif
}
MA_API Mv ma_mutex_lock(ma_mutex*pMutex)
{
if (pMutex==NULL) {
MA_ASSERT(MA_FALSE);
Mr;
}
#if defined(MA_POSIX)
ma_mutex_lock__posix(pMutex);
#elif defined(MA_WIN32)
ma_mutex_lock__win32(pMutex);
#endif
}
MA_API Mv ma_mutex_unlock(ma_mutex*pMutex)
{
if (pMutex==NULL) {
MA_ASSERT(MA_FALSE);
Mr;
}
#if defined(MA_POSIX)
ma_mutex_unlock__posix(pMutex);
#elif defined(MA_WIN32)
ma_mutex_unlock__win32(pMutex);
#endif
}
MA_API Me ma_event_init(ma_event*pEvent)
{
if (pEvent==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_event_init__posix(pEvent);
#elif defined(MA_WIN32)
Mr ma_event_init__win32(pEvent);
#endif
}
#if 0
static Me ma_event_alloc_and_init(ma_event**ppEvent,ma_allocation_callbacks*pAllocationCallbacks)
{
Me Mf;
ma_event*pEvent;
if (ppEvent==NULL) {
Mr MA_INVALID_ARGS;
}
*ppEvent=NULL;
pEvent=ma_malloc(sizeof(*pEvent),pAllocationCallbacks);
if (pEvent==NULL) {
Mr MA_OUT_OF_MEMORY;
}
Mf=ma_event_init(pEvent);
if (Mf !=Ms) {
ma_free(pEvent,pAllocationCallbacks);
Mr Mf;
}
*ppEvent=pEvent;
Mr Mf;
}
#endif
MA_API Mv ma_event_uninit(ma_event*pEvent)
{
if (pEvent==NULL) {
Mr;
}
#if defined(MA_POSIX)
ma_event_uninit__posix(pEvent);
#elif defined(MA_WIN32)
ma_event_uninit__win32(pEvent);
#endif
}
#if 0
static Mv ma_event_uninit_and_free(ma_event*pEvent,ma_allocation_callbacks*pAllocationCallbacks)
{
if (pEvent==NULL) {
Mr;
}
ma_event_uninit(pEvent);
ma_free(pEvent,pAllocationCallbacks);
}
#endif
MA_API Me ma_event_wait(ma_event*pEvent)
{
if (pEvent==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_event_wait__posix(pEvent);
#elif defined(MA_WIN32)
Mr ma_event_wait__win32(pEvent);
#endif
}
MA_API Me ma_event_signal(ma_event*pEvent)
{
if (pEvent==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_event_signal__posix(pEvent);
#elif defined(MA_WIN32)
Mr ma_event_signal__win32(pEvent);
#endif
}
MA_API Me ma_semaphore_init(int initialValue,ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_semaphore_init__posix(initialValue,pSemaphore);
#elif defined(MA_WIN32)
Mr ma_semaphore_init__win32(initialValue,pSemaphore);
#endif
}
MA_API Mv ma_semaphore_uninit(ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
MA_ASSERT(MA_FALSE);
Mr;
}
#if defined(MA_POSIX)
ma_semaphore_uninit__posix(pSemaphore);
#elif defined(MA_WIN32)
ma_semaphore_uninit__win32(pSemaphore);
#endif
}
MA_API Me ma_semaphore_wait(ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_semaphore_wait__posix(pSemaphore);
#elif defined(MA_WIN32)
Mr ma_semaphore_wait__win32(pSemaphore);
#endif
}
MA_API Me ma_semaphore_release(ma_semaphore*pSemaphore)
{
if (pSemaphore==NULL) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
#if defined(MA_POSIX)
Mr ma_semaphore_release__posix(pSemaphore);
#elif defined(MA_WIN32)
Mr ma_semaphore_release__win32(pSemaphore);
#endif
}
#else
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif
#define MA_FENCE_COUNTER_MAX 0x7FFFFFFF
MA_API Me ma_fence_init(ma_fence*pFence)
{
if (pFence==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFence);
pFence->counter=0;
#ifndef MA_NO_THREADING
{
Me Mf;
Mf=ma_event_init(&pFence->e);
if (Mf !=Ms) {
Mr Mf;
}
}
#endif
Mr Ms;
}
MA_API Mv ma_fence_uninit(ma_fence*pFence)
{
if (pFence==NULL) {
Mr;
}
#ifndef MA_NO_THREADING
{
ma_event_uninit(&pFence->e);
}
#endif
MA_ZERO_OBJECT(pFence);
}
MA_API Me ma_fence_acquire(ma_fence*pFence)
{
if (pFence==NULL) {
Mr MA_INVALID_ARGS;
}
for (;;) {
M3 oldCounter=ma_atomic_load_32(&pFence->counter);
M3 newCounter=oldCounter+1;
if (newCounter>MA_FENCE_COUNTER_MAX) {
MA_ASSERT(MA_FALSE);
Mr MA_OUT_OF_RANGE;
}
if (ma_atomic_compare_exchange_weak_32(&pFence->counter,&oldCounter,newCounter)) {
Mr Ms;
} else {
if (oldCounter==MA_FENCE_COUNTER_MAX) {
MA_ASSERT(MA_FALSE);
Mr MA_OUT_OF_RANGE;
}
}
}
}
MA_API Me ma_fence_release(ma_fence*pFence)
{
if (pFence==NULL) {
Mr MA_INVALID_ARGS;
}
for (;;) {
M3 oldCounter=ma_atomic_load_32(&pFence->counter);
M3 newCounter=oldCounter-1;
if (oldCounter==0) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_OPERATION;
}
if (ma_atomic_compare_exchange_weak_32(&pFence->counter,&oldCounter,newCounter)) {
#ifndef MA_NO_THREADING
{
if (newCounter==0) {
 ma_event_signal(&pFence->e);
}
}
#endif
Mr Ms;
} else {
if (oldCounter==0) {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_OPERATION;
}
}
}
}
MA_API Me ma_fence_wait(ma_fence*pFence)
{
if (pFence==NULL) {
Mr MA_INVALID_ARGS;
}
for (;;) {
M3 counter;
counter=ma_atomic_load_32(&pFence->counter);
if (counter==0) {
Mr Ms;
}
#ifndef MA_NO_THREADING
{
Me Mf;
Mf=ma_event_wait(&pFence->e);
if (Mf !=Ms) {
Mr Mf;
}
}
#endif
}
}
MA_API Me ma_async_notification_signal(ma_async_notification*pNotification)
{
ma_async_notification_callbacks*pNotificationCallbacks=(ma_async_notification_callbacks*)pNotification;
if (pNotification==NULL) {
Mr MA_INVALID_ARGS;
}
if (pNotificationCallbacks->onSignal==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
pNotificationCallbacks->onSignal(pNotification);
Mr MA_INVALID_ARGS;
}
static Mv ma_async_notification_poll__on_signal(ma_async_notification*pNotification)
{
((ma_async_notification_poll*)pNotification)->signalled=MA_TRUE;
}
MA_API Me ma_async_notification_poll_init(ma_async_notification_poll*pNotificationPoll)
{
if (pNotificationPoll==NULL) {
Mr MA_INVALID_ARGS;
}
pNotificationPoll->cb.onSignal=ma_async_notification_poll__on_signal;
pNotificationPoll->signalled=MA_FALSE;
Mr Ms;
}
MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll*pNotificationPoll)
{
if (pNotificationPoll==NULL) {
Mr MA_FALSE;
}
Mr pNotificationPoll->signalled;
}
static Mv ma_async_notification_event__on_signal(ma_async_notification*pNotification)
{
ma_async_notification_event_signal((ma_async_notification_event*)pNotification);
}
MA_API Me ma_async_notification_event_init(ma_async_notification_event*pNotificationEvent)
{
if (pNotificationEvent==NULL) {
Mr MA_INVALID_ARGS;
}
pNotificationEvent->cb.onSignal=ma_async_notification_event__on_signal;
#ifndef MA_NO_THREADING
{
Me Mf;
Mf=ma_event_init(&pNotificationEvent->e);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
#else
{
Mr MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API Me ma_async_notification_event_uninit(ma_async_notification_event*pNotificationEvent)
{
if (pNotificationEvent==NULL) {
Mr MA_INVALID_ARGS;
}
#ifndef MA_NO_THREADING
{
ma_event_uninit(&pNotificationEvent->e);
Mr Ms;
}
#else
{
Mr MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API Me ma_async_notification_event_wait(ma_async_notification_event*pNotificationEvent)
{
if (pNotificationEvent==NULL) {
Mr MA_INVALID_ARGS;
}
#ifndef MA_NO_THREADING
{
Mr ma_event_wait(&pNotificationEvent->e);
}
#else
{
Mr MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API Me ma_async_notification_event_signal(ma_async_notification_event*pNotificationEvent)
{
if (pNotificationEvent==NULL) {
Mr MA_INVALID_ARGS;
}
#ifndef MA_NO_THREADING
{
Mr ma_event_signal(&pNotificationEvent->e);
}
#else
{
Mr MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_slot_allocator_config ma_slot_allocator_config_init(M3 capacity)
{
ma_slot_allocator_config config;
MA_ZERO_OBJECT(&config);
config.capacity=capacity;
Mr config;
}
static MA_INLINE M3 ma_slot_allocator_calculate_group_capacity(M3 slotCapacity)
{
M3 cap=slotCapacity / 32;
if ((slotCapacity % 32) !=0) {
cap+=1;
}
Mr cap;
}
static MA_INLINE M3 ma_slot_allocator_group_capacity(const ma_slot_allocator*pAllocator)
{
Mr ma_slot_allocator_calculate_group_capacity(pAllocator->capacity);
}
typedef struct
{
size_t sizeInBytes;
size_t groupsOffset;
size_t slotsOffset;
} ma_slot_allocator_heap_layout;
static Me ma_slot_allocator_get_heap_layout(const ma_slot_allocator_config*Mo,ma_slot_allocator_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->capacity==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->groupsOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(ma_slot_allocator_calculate_group_capacity(Mo->capacity)*sizeof(ma_slot_allocator_group));
pHeapLayout->slotsOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(Mo->capacity*sizeof(M3));
Mr Ms;
}
MA_API Me ma_slot_allocator_get_heap_size(const ma_slot_allocator_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_slot_allocator_heap_layout layout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_slot_allocator_get_heap_layout(Mo,&layout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=layout.sizeInBytes;
Mr Mf;
}
MA_API Me ma_slot_allocator_init_preallocated(const ma_slot_allocator_config*Mo,Mv*pHeap,ma_slot_allocator*pAllocator)
{
Me Mf;
ma_slot_allocator_heap_layout heapLayout;
if (pAllocator==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pAllocator);
if (pHeap==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_slot_allocator_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pAllocator->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pAllocator->pGroups=(ma_slot_allocator_group*)ma_offset_ptr(pHeap,heapLayout.groupsOffset);
pAllocator->pSlots=(M3*)ma_offset_ptr(pHeap,heapLayout.slotsOffset);
pAllocator->capacity=Mo->capacity;
Mr Ms;
}
MA_API Me ma_slot_allocator_init(const ma_slot_allocator_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_slot_allocator*pAllocator)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_slot_allocator_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_slot_allocator_init_preallocated(Mo,pHeap,pAllocator);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pAllocator->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_slot_allocator_uninit(ma_slot_allocator*pAllocator,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pAllocator==NULL) {
Mr;
}
if (pAllocator->_ownsHeap) {
ma_free(pAllocator->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_slot_allocator_alloc(ma_slot_allocator*pAllocator,M6*pSlot)
{
M3 iAttempt;
const M3 maxAttempts=2;
if (pAllocator==NULL||pSlot==NULL) {
Mr MA_INVALID_ARGS;
}
for (iAttempt=0; iAttempt<maxAttempts; iAttempt+=1) {
M3 iGroup;
for (iGroup=0; iGroup<ma_slot_allocator_group_capacity(pAllocator); iGroup+=1) {
for (;;) {
M3 oldBitfield;
M3 newBitfield;
M3 bitOffset;
oldBitfield=ma_atomic_load_32(&pAllocator->pGroups[iGroup].bitfield);
if (oldBitfield==0xFFFFFFFF) {
 break;
}
bitOffset=ma_ffs_32(~oldBitfield);
MA_ASSERT(bitOffset<32);
newBitfield=oldBitfield|(1<<bitOffset);
if (ma_atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield,oldBitfield,newBitfield)==oldBitfield) {
 M3 slotIndex;
 ma_atomic_fetch_add_32(&pAllocator->count,1);
 slotIndex=(iGroup<<5)+bitOffset;
 if (slotIndex>=pAllocator->capacity) {
 Mr MA_OUT_OF_MEMORY;
 }
 pAllocator->pSlots[slotIndex]+=1;
*pSlot=(((M6)pAllocator->pSlots[slotIndex]<<32)|slotIndex);
 Mr Ms;
}
}
}
if (pAllocator->count<pAllocator->capacity) {
ma_yield();
} else {
Mr MA_OUT_OF_MEMORY;
}
}
Mr MA_OUT_OF_MEMORY;
}
MA_API Me ma_slot_allocator_free(ma_slot_allocator*pAllocator,M6 slot)
{
M3 iGroup;
M3 iBit;
if (pAllocator==NULL) {
Mr MA_INVALID_ARGS;
}
iGroup=(M3)((slot&0xFFFFFFFF)>>5);
iBit=(M3)((slot&0xFFFFFFFF)&31);
if (iGroup>=ma_slot_allocator_group_capacity(pAllocator)) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(iBit<32);
while (ma_atomic_load_32(&pAllocator->count)>0) {
M3 oldBitfield;
M3 newBitfield;
oldBitfield=ma_atomic_load_32(&pAllocator->pGroups[iGroup].bitfield);
newBitfield=oldBitfield&~(1<<iBit);
#if defined(MA_DEBUG_OUTPUT)
{
if ((oldBitfield&(1<<iBit))==0) {
MA_ASSERT(MA_FALSE);
}
}
#endif
if (ma_atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield,oldBitfield,newBitfield)==oldBitfield) {
ma_atomic_fetch_sub_32(&pAllocator->count,1);
Mr Ms;
}
}
Mr MA_INVALID_OPERATION;
}
#define MA_JOB_ID_NONE ~((M6)0)
#define MA_JOB_SLOT_NONE (ma_uint16)(~0)
static MA_INLINE M3 ma_job_extract_refcount(M6 toc)
{
Mr (M3)(toc>>32);
}
static MA_INLINE ma_uint16 ma_job_extract_slot(M6 toc)
{
Mr (ma_uint16)(toc&0x0000FFFF);
}
static MA_INLINE ma_uint16 ma_job_extract_code(M6 toc)
{
Mr (ma_uint16)((toc&0xFFFF0000)>>16);
}
static MA_INLINE M6 ma_job_toc_to_allocation(M6 toc)
{
Mr ((M6)ma_job_extract_refcount(toc)<<32)|(M6)ma_job_extract_slot(toc);
}
static MA_INLINE M6 ma_job_set_refcount(M6 toc,M3 refcount)
{
toc=toc&~((M6)0xFFFFFFFF<<32);
toc=toc|((M6)refcount<<32);
Mr toc;
}
MA_API ma_job ma_job_init(ma_uint16 code)
{
ma_job job;
MA_ZERO_OBJECT(&job);
job.toc.breakup.code=code;
job.toc.breakup.slot=MA_JOB_SLOT_NONE;
job.next=MA_JOB_ID_NONE;
Mr job;
}
static Me ma_job_process__noop(ma_job*pJob);
static Me ma_job_process__quit(ma_job*pJob);
static Me ma_job_process__custom(ma_job*pJob);
#if !defined(MA_NO_DEVICE_IO)
static Me ma_job_process__device__aaudio_reroute(ma_job*pJob);
#endif
static ma_job_proc g_jobVTable[MA_JOB_TYPE_COUNT]=
{
ma_job_process__quit,ma_job_process__custom,
#if !defined(MA_NO_DEVICE_IO)
ma_job_process__device__aaudio_reroute
#endif
};
MA_API Me ma_job_process(ma_job*pJob)
{
if (pJob==NULL) {
Mr MA_INVALID_ARGS;
}
if (pJob->toc.breakup.code>=MA_JOB_TYPE_COUNT) {
Mr MA_INVALID_OPERATION;
}
Mr g_jobVTable[pJob->toc.breakup.code](pJob);
}
static Me ma_job_process__noop(ma_job*pJob)
{
MA_ASSERT(pJob !=NULL);
(Mv)pJob;
Mr Ms;
}
static Me ma_job_process__quit(ma_job*pJob)
{
Mr ma_job_process__noop(pJob);
}
static Me ma_job_process__custom(ma_job*pJob)
{
MA_ASSERT(pJob !=NULL);
if (pJob->data.custom.proc==NULL) {
Mr Ms;
}
Mr pJob->data.custom.proc(pJob);
}
MA_API ma_job_queue_config ma_job_queue_config_init(M3 flags,M3 capacity)
{
ma_job_queue_config config;
config.flags=flags;
config.capacity=capacity;
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t allocatorOffset;
size_t jobsOffset;
} ma_job_queue_heap_layout;
static Me ma_job_queue_get_heap_layout(const ma_job_queue_config*Mo,ma_job_queue_heap_layout*pHeapLayout)
{
Me Mf;
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->capacity==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
{
ma_slot_allocator_config allocatorConfig;
size_t allocatorHeapSizeInBytes;
allocatorConfig=ma_slot_allocator_config_init(Mo->capacity);
Mf=ma_slot_allocator_get_heap_size(&allocatorConfig,&allocatorHeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->allocatorOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=allocatorHeapSizeInBytes;
}
pHeapLayout->jobsOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(Mo->capacity*sizeof(ma_job));
Mr Ms;
}
MA_API Me ma_job_queue_get_heap_size(const ma_job_queue_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_job_queue_heap_layout layout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_job_queue_get_heap_layout(Mo,&layout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=layout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_job_queue_init_preallocated(const ma_job_queue_config*Mo,Mv*pHeap,ma_job_queue*pQueue)
{
Me Mf;
ma_job_queue_heap_layout heapLayout;
ma_slot_allocator_config allocatorConfig;
if (pQueue==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pQueue);
Mf=ma_job_queue_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pQueue->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pQueue->flags=Mo->flags;
pQueue->capacity=Mo->capacity;
pQueue->pJobs=(ma_job*)ma_offset_ptr(pHeap,heapLayout.jobsOffset);
allocatorConfig=ma_slot_allocator_config_init(Mo->capacity);
Mf=ma_slot_allocator_init_preallocated(&allocatorConfig,ma_offset_ptr(pHeap,heapLayout.allocatorOffset),&pQueue->allocator);
if (Mf !=Ms) {
Mr Mf;
}
if ((pQueue->flags&MA_JOB_QUEUE_FLAG_NON_BLOCKING)==0) {
#ifndef MA_NO_THREADING
{
ma_semaphore_init(0,&pQueue->sem);
}
#else
{
Mr MA_INVALID_OPERATION;
}
#endif
}
ma_slot_allocator_alloc(&pQueue->allocator,&pQueue->head);
pQueue->pJobs[ma_job_extract_slot(pQueue->head)].next=MA_JOB_ID_NONE;
pQueue->tail=pQueue->head;
Mr Ms;
}
MA_API Me ma_job_queue_init(const ma_job_queue_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_job_queue*pQueue)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_job_queue_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_job_queue_init_preallocated(Mo,pHeap,pQueue);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pQueue->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_job_queue_uninit(ma_job_queue*pQueue,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pQueue==NULL) {
Mr;
}
if ((pQueue->flags&MA_JOB_QUEUE_FLAG_NON_BLOCKING)==0) {
#ifndef MA_NO_THREADING
{
ma_semaphore_uninit(&pQueue->sem);
}
#else
{
MA_ASSERT(MA_FALSE);
}
#endif
}
ma_slot_allocator_uninit(&pQueue->allocator,pAllocationCallbacks);
if (pQueue->_ownsHeap) {
ma_free(pQueue->_pHeap,pAllocationCallbacks);
}
}
static ma_bool32 ma_job_queue_cas(volatile M6*dst,M6 expected,M6 desired)
{
Mr ma_atomic_compare_and_swap_64(dst,expected,ma_job_set_refcount(desired,ma_job_extract_refcount(expected)+1))==expected;
}
MA_API Me ma_job_queue_post(ma_job_queue*pQueue,const ma_job*pJob)
{
Me Mf;
M6 slot;
M6 tail;
M6 next;
if (pQueue==NULL||pJob==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_slot_allocator_alloc(&pQueue->allocator,&slot);
if (Mf !=Ms) {
Mr Mf;
}
MA_ASSERT(ma_job_extract_slot(slot)<pQueue->capacity);
pQueue->pJobs[ma_job_extract_slot(slot)]=*pJob;
pQueue->pJobs[ma_job_extract_slot(slot)].toc.allocation=slot;
pQueue->pJobs[ma_job_extract_slot(slot)].toc.breakup.code=pJob->toc.breakup.code;
pQueue->pJobs[ma_job_extract_slot(slot)].next=MA_JOB_ID_NONE;
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock_lock(&pQueue->lock);
#endif
{
for (;;) {
tail=ma_atomic_load_64(&pQueue->tail);
next=ma_atomic_load_64(&pQueue->pJobs[ma_job_extract_slot(tail)].next);
if (ma_job_toc_to_allocation(tail)==ma_job_toc_to_allocation(ma_atomic_load_64(&pQueue->tail))) {
if (ma_job_extract_slot(next)==0xFFFF) {
 if (ma_job_queue_cas(&pQueue->pJobs[ma_job_extract_slot(tail)].next,next,slot)) {
 break;
 }
} else {
 ma_job_queue_cas(&pQueue->tail,tail,ma_job_extract_slot(next));
}
}
}
ma_job_queue_cas(&pQueue->tail,tail,slot);
}
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock_unlock(&pQueue->lock);
#endif
if ((pQueue->flags&MA_JOB_QUEUE_FLAG_NON_BLOCKING)==0) {
#ifndef MA_NO_THREADING
{
ma_semaphore_release(&pQueue->sem);
}
#else
{
MA_ASSERT(MA_FALSE);
}
#endif
}
Mr Ms;
}
MA_API Me ma_job_queue_next(ma_job_queue*pQueue,ma_job*pJob)
{
M6 head;
M6 tail;
M6 next;
if (pQueue==NULL||pJob==NULL) {
Mr MA_INVALID_ARGS;
}
if ((pQueue->flags&MA_JOB_QUEUE_FLAG_NON_BLOCKING)==0) {
#ifndef MA_NO_THREADING
{
ma_semaphore_wait(&pQueue->sem);
}
#else
{
MA_ASSERT(MA_FALSE);
}
#endif
}
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock_lock(&pQueue->lock);
#endif
{
for (;;) {
head=ma_atomic_load_64(&pQueue->head);
tail=ma_atomic_load_64(&pQueue->tail);
next=ma_atomic_load_64(&pQueue->pJobs[ma_job_extract_slot(head)].next);
if (ma_job_toc_to_allocation(head)==ma_job_toc_to_allocation(ma_atomic_load_64(&pQueue->head))) {
if (ma_job_extract_slot(head)==ma_job_extract_slot(tail)) {
 if (ma_job_extract_slot(next)==0xFFFF) {
 #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
 ma_spinlock_unlock(&pQueue->lock);
 #endif
 Mr MA_NO_DATA_AVAILABLE;
 }
 ma_job_queue_cas(&pQueue->tail,tail,ma_job_extract_slot(next));
} else {
*pJob=pQueue->pJobs[ma_job_extract_slot(next)];
 if (ma_job_queue_cas(&pQueue->head,head,ma_job_extract_slot(next))) {
 break;
 }
}
}
}
}
#ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
ma_spinlock_unlock(&pQueue->lock);
#endif
ma_slot_allocator_free(&pQueue->allocator,head);
if (pJob->toc.breakup.code==MA_JOB_TYPE_QUIT) {
ma_job_queue_post(pQueue,pJob);
Mr MA_CANCELLED;
}
Mr Ms;
}
#ifdef MA_POSIX
#ifndef MA_NO_RUNTIME_LINKING
#include <dlfcn.h>
#endif
#endif
MA_API ma_handle ma_dlopen(ma_log*pLog,const char*filename)
{
#ifndef MA_NO_RUNTIME_LINKING
ma_handle handle;
ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename);
#ifdef MA_WIN32
#if !defined(MA_WIN32_UWP)||!(defined(WINAPI_FAMILY)&&((defined(WINAPI_FAMILY_PHONE_APP)&&WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)))
handle=(ma_handle)LoadLibraryA(filename);
#else
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
if (handle==NULL) {
ma_log_postf(pLog, MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename);
}
Mr handle;
#else
(Mv)pLog;
(Mv)filename;
Mr NULL;
#endif
}
MA_API Mv ma_dlclose(ma_log*pLog,ma_handle handle)
{
#ifndef MA_NO_RUNTIME_LINKING
#ifdef MA_WIN32
FreeLibrary((HMODULE)handle);
#else
#if !defined(MA_ANDROID)||(defined(__ANDROID_API__)&&__ANDROID_API__>=28)
{
dlclose((Mv*)handle);
}
#else
{
(Mv)handle;
}
#endif
#endif
(Mv)pLog;
#else
(Mv)pLog;
(Mv)handle;
#endif
}
MA_API ma_proc ma_dlsym(ma_log*pLog,ma_handle handle,const char*symbol)
{
#ifndef MA_NO_RUNTIME_LINKING
ma_proc proc;
ma_log_postf(pLog, MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol);
#ifdef _WIN32
proc=(ma_proc)GetProcAddress((HMODULE)handle,symbol);
#else
#if (defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=8)))||defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
proc=(ma_proc)dlsym((Mv*)handle,symbol);
#if (defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=8)))||defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif
if (proc==NULL) {
ma_log_postf(pLog, MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol);
}
(Mv)pLog;
Mr proc;
#else
(Mv)pLog;
(Mv)handle;
(Mv)symbol;
Mr NULL;
#endif
}
#ifndef MA_NO_RUNTIME_LINKING
#if defined(MA_EMSCRIPTEN)||defined(MA_ORBIS)||defined(MA_PROSPERO)
#define MA_NO_RUNTIME_LINKING
#endif
#endif
#ifdef MA_APPLE
#include <AvailabilityMacros.h>
#endif
#ifndef MA_NO_DEVICE_IO
#if defined(MA_APPLE)&&(MAC_OS_X_VERSION_MIN_REQUIRED<101200)
#include <mach/mach_time.h>
#endif
#ifdef MA_POSIX
#include <sys/types.h>
#include <unistd.h>
#ifndef MA_NO_RUNTIME_LINKING
#include <dlfcn.h>
#endif
#endif
#ifndef MA_AAUDIO_MIN_ANDROID_SDK_VERSION
#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 27
#endif
MA_API Mv ma_device_info_add_native_data_format(ma_device_info*pDeviceInfo,ma_format format,M3 Mh,M3 sampleRate,M3 flags)
{
if (pDeviceInfo==NULL) {
Mr;
}
if (pDeviceInfo->nativeDataFormatCount<ma_countof(pDeviceInfo->nativeDataFormats)) {
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=format;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=Mh;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=sampleRate;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=flags;
pDeviceInfo->nativeDataFormatCount+=1;
}
}
typedef struct
{
ma_backend backend;
const char*pName;
} ma_backend_info;
static ma_backend_info gBackendInfo[]=
{
{ma_backend_wasapi, "WASAPI"},{ma_backend_dsound, "DirectSound"},{ma_backend_winmm, "WinMM"},{ma_backend_coreaudio, "Core Audio"},{ma_backend_sndio, "sndio"},{ma_backend_audio4, "audio(4)"},{ma_backend_oss, "OSS"},{ma_backend_pulseaudio, "PulseAudio"},{ma_backend_alsa, "ALSA"},{ma_backend_jack, "JACK"},{ma_backend_aaudio, "AAudio"},{ma_backend_opensl, "OpenSL|ES"},{ma_backend_webaudio, "Web Audio"},{ma_backend_custom, "Custom"},{ma_backend_null, "Null"}
};
MA_API const char*ma_get_backend_name(ma_backend backend)
{
if (backend<0||backend>=(int)ma_countof(gBackendInfo)) {
Mr "Unknown";
}
Mr gBackendInfo[backend].pName;
}
MA_API Me ma_get_backend_from_name(const char*pBackendName,ma_backend*pBackend)
{
size_t iBackend;
if (pBackendName==NULL) {
Mr MA_INVALID_ARGS;
}
for (iBackend=0; iBackend<ma_countof(gBackendInfo); iBackend+=1) {
if (ma_strcmp(pBackendName,gBackendInfo[iBackend].pName)==0) {
if (pBackend !=NULL) {
*pBackend=gBackendInfo[iBackend].backend;
}
Mr Ms;
}
}
Mr MA_INVALID_ARGS;
}
MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
{
switch (backend)
{
case ma_backend_wasapi:
#if defined(MA_HAS_WASAPI)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_dsound:
#if defined(MA_HAS_DSOUND)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_winmm:
#if defined(MA_HAS_WINMM)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_coreaudio:
#if defined(MA_HAS_COREAUDIO)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_sndio:
#if defined(MA_HAS_SNDIO)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_audio4:
#if defined(MA_HAS_AUDIO4)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_oss:
#if defined(MA_HAS_OSS)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_pulseaudio:
#if defined(MA_HAS_PULSEAUDIO)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_alsa:
#if defined(MA_HAS_ALSA)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_jack:
#if defined(MA_HAS_JACK)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_aaudio:
#if defined(MA_HAS_AAUDIO)
#if defined(MA_ANDROID)
{
Mr ma_android_sdk_version()>=MA_AAUDIO_MIN_ANDROID_SDK_VERSION;
}
#else
Mr MA_FALSE;
#endif
#else
Mr MA_FALSE;
#endif
case ma_backend_opensl:
#if defined(MA_HAS_OPENSL)
#if defined(MA_ANDROID)
{
Mr ma_android_sdk_version()>=9;
}
#else
Mr MA_TRUE;
#endif
#else
Mr MA_FALSE;
#endif
case ma_backend_webaudio:
#if defined(MA_HAS_WEBAUDIO)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_custom:
#if defined(MA_HAS_CUSTOM)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
case ma_backend_null:
#if defined(MA_HAS_NULL)
Mr MA_TRUE;
#else
Mr MA_FALSE;
#endif
default:Mr MA_FALSE;
}
}
MA_API Me ma_get_enabled_backends(ma_backend*pBackends,size_t backendCap,size_t*pBackendCount)
{
size_t backendCount;
size_t iBackend;
Me Mf=Ms;
if (pBackendCount==NULL) {
Mr MA_INVALID_ARGS;
}
backendCount=0;
for (iBackend=0; iBackend<=ma_backend_null; iBackend+=1) {
ma_backend backend=(ma_backend)iBackend;
if (ma_is_backend_enabled(backend)) {
if (backendCount==backendCap) {
Mf=MA_NO_SPACE;
break;
} else {
pBackends[backendCount]=backend;
backendCount+=1;
}
}
}
if (pBackendCount !=NULL) {
*pBackendCount=backendCount;
}
Mr Mf;
}
MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend)
{
switch (backend)
{
case ma_backend_wasapi:Mr MA_TRUE;
case ma_backend_dsound:Mr MA_FALSE;
case ma_backend_winmm:Mr MA_FALSE;
case ma_backend_coreaudio:Mr MA_FALSE;
case ma_backend_sndio:Mr MA_FALSE;
case ma_backend_audio4:Mr MA_FALSE;
case ma_backend_oss:Mr MA_FALSE;
case ma_backend_pulseaudio:Mr MA_FALSE;
case ma_backend_alsa:Mr MA_FALSE;
case ma_backend_jack:Mr MA_FALSE;
case ma_backend_aaudio:Mr MA_FALSE;
case ma_backend_opensl:Mr MA_FALSE;
case ma_backend_webaudio:Mr MA_FALSE;
case ma_backend_custom:Mr MA_FALSE;
case ma_backend_null:Mr MA_FALSE;
default:Mr MA_FALSE;
}
}
#if defined(MA_WIN32)
#define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001)
#define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002)
#define MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE ((HRESULT)0x88890003)
#define MA_AUDCLNT_E_DEVICE_INVALIDATED ((HRESULT)0x88890004)
#define MA_AUDCLNT_E_NOT_STOPPED ((HRESULT)0x88890005)
#define MA_AUDCLNT_E_BUFFER_TOO_LARGE ((HRESULT)0x88890006)
#define MA_AUDCLNT_E_OUT_OF_ORDER ((HRESULT)0x88890007)
#define MA_AUDCLNT_E_UNSUPPORTED_FORMAT ((HRESULT)0x88890008)
#define MA_AUDCLNT_E_INVALID_SIZE ((HRESULT)0x88890009)
#define MA_AUDCLNT_E_DEVICE_IN_USE ((HRESULT)0x8889000A)
#define MA_AUDCLNT_E_BUFFER_OPERATION_PENDING ((HRESULT)0x8889000B)
#define MA_AUDCLNT_E_THREAD_NOT_REGISTERED ((HRESULT)0x8889000C)
#define MA_AUDCLNT_E_NO_SINGLE_PROCESS ((HRESULT)0x8889000D)
#define MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED ((HRESULT)0x8889000E)
#define MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED ((HRESULT)0x8889000F)
#define MA_AUDCLNT_E_SERVICE_NOT_RUNNING ((HRESULT)0x88890010)
#define MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED ((HRESULT)0x88890011)
#define MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY ((HRESULT)0x88890012)
#define MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL ((HRESULT)0x88890013)
#define MA_AUDCLNT_E_EVENTHANDLE_NOT_SET ((HRESULT)0x88890014)
#define MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE ((HRESULT)0x88890015)
#define MA_AUDCLNT_E_BUFFER_SIZE_ERROR ((HRESULT)0x88890016)
#define MA_AUDCLNT_E_CPUUSAGE_EXCEEDED ((HRESULT)0x88890017)
#define MA_AUDCLNT_E_BUFFER_ERROR ((HRESULT)0x88890018)
#define MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED ((HRESULT)0x88890019)
#define MA_AUDCLNT_E_INVALID_DEVICE_PERIOD ((HRESULT)0x88890020)
#define MA_AUDCLNT_E_INVALID_STREAM_FLAG ((HRESULT)0x88890021)
#define MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE ((HRESULT)0x88890022)
#define MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES ((HRESULT)0x88890023)
#define MA_AUDCLNT_E_OFFLOAD_MODE_ONLY ((HRESULT)0x88890024)
#define MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY ((HRESULT)0x88890025)
#define MA_AUDCLNT_E_RESOURCES_INVALIDATED ((HRESULT)0x88890026)
#define MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED ((HRESULT)0x88890027)
#define MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED ((HRESULT)0x88890028)
#define MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED ((HRESULT)0x88890029)
#define MA_AUDCLNT_E_HEADTRACKING_ENABLED ((HRESULT)0x88890030)
#define MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED ((HRESULT)0x88890040)
#define MA_AUDCLNT_S_BUFFER_EMPTY ((HRESULT)0x08890001)
#define MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED ((HRESULT)0x08890002)
#define MA_AUDCLNT_S_POSITION_STALLED ((HRESULT)0x08890003)
#define MA_DS_OK ((HRESULT)0)
#define MA_DS_NO_VIRTUALIZATION ((HRESULT)0x0878000A)
#define MA_DSERR_ALLOCATED ((HRESULT)0x8878000A)
#define MA_DSERR_CONTROLUNAVAIL ((HRESULT)0x8878001E)
#define MA_DSERR_INVALIDPARAM ((HRESULT)0x80070057)
#define MA_DSERR_INVALIDCALL ((HRESULT)0x88780032)
#define MA_DSERR_GENERIC ((HRESULT)0x80004005)
#define MA_DSERR_PRIOLEVELNEEDED ((HRESULT)0x88780046)
#define MA_DSERR_OUTOFMEMORY ((HRESULT)0x8007000E)
#define MA_DSERR_BADFORMAT ((HRESULT)0x88780064)
#define MA_DSERR_UNSUPPORTED ((HRESULT)0x80004001)
#define MA_DSERR_NODRIVER ((HRESULT)0x88780078)
#define MA_DSERR_ALREADYINITIALIZED ((HRESULT)0x88780082)
#define MA_DSERR_NOAGGREGATION ((HRESULT)0x80040110)
#define MA_DSERR_BUFFERLOST ((HRESULT)0x88780096)
#define MA_DSERR_OTHERAPPHASPRIO ((HRESULT)0x887800A0)
#define MA_DSERR_UNINITIALIZED ((HRESULT)0x887800AA)
#define MA_DSERR_NOINTERFACE ((HRESULT)0x80004002)
#define MA_DSERR_ACCESSDENIED ((HRESULT)0x80070005)
#define MA_DSERR_BUFFERTOOSMALL ((HRESULT)0x887800B4)
#define MA_DSERR_DS8_REQUIRED ((HRESULT)0x887800BE)
#define MA_DSERR_SENDLOOP ((HRESULT)0x887800C8)
#define MA_DSERR_BADSENDBUFFERGUID ((HRESULT)0x887800D2)
#define MA_DSERR_OBJECTNOTFOUND ((HRESULT)0x88781161)
#define MA_DSERR_FXUNAVAILABLE ((HRESULT)0x887800DC)
static Me ma_result_from_HRESULT(HRESULT hr)
{
switch (hr)
{
case NOERROR:Mr Ms;
case E_POINTER:Mr MA_INVALID_ARGS;
case E_UNEXPECTED:Mr MA_ERROR;
case E_NOTIMPL:Mr MA_NOT_IMPLEMENTED;
case E_OUTOFMEMORY:Mr MA_OUT_OF_MEMORY;
case E_INVALIDARG:Mr MA_INVALID_ARGS;
case E_NOINTERFACE:Mr MA_API_NOT_FOUND;
case E_HANDLE:Mr MA_INVALID_ARGS;
case E_ABORT:Mr MA_ERROR;
case E_FAIL:Mr MA_ERROR;
case E_ACCESSDENIED:Mr MA_ACCESS_DENIED;
case MA_AUDCLNT_E_NOT_INITIALIZED:Mr MA_DEVICE_NOT_INITIALIZED;
case MA_AUDCLNT_E_ALREADY_INITIALIZED:Mr MA_DEVICE_ALREADY_INITIALIZED;
case MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_DEVICE_INVALIDATED:Mr MA_UNAVAILABLE;
case MA_AUDCLNT_E_NOT_STOPPED:Mr MA_DEVICE_NOT_STOPPED;
case MA_AUDCLNT_E_BUFFER_TOO_LARGE:Mr MA_TOO_BIG;
case MA_AUDCLNT_E_OUT_OF_ORDER:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_UNSUPPORTED_FORMAT:Mr MA_FORMAT_NOT_SUPPORTED;
case MA_AUDCLNT_E_INVALID_SIZE:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_DEVICE_IN_USE:Mr MA_BUSY;
case MA_AUDCLNT_E_BUFFER_OPERATION_PENDING:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_THREAD_NOT_REGISTERED:Mr MA_DOES_NOT_EXIST;
case MA_AUDCLNT_E_NO_SINGLE_PROCESS:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:Mr MA_SHARE_MODE_NOT_SUPPORTED;
case MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED:Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
case MA_AUDCLNT_E_SERVICE_NOT_RUNNING:Mr MA_NOT_CONNECTED;
case MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY:Mr MA_SHARE_MODE_NOT_SUPPORTED;
case MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_EVENTHANDLE_NOT_SET:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_BUFFER_SIZE_ERROR:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_CPUUSAGE_EXCEEDED:Mr MA_ERROR;
case MA_AUDCLNT_E_BUFFER_ERROR:Mr MA_ERROR;
case MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_INVALID_DEVICE_PERIOD:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_INVALID_STREAM_FLAG:Mr MA_INVALID_ARGS;
case MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES:Mr MA_OUT_OF_MEMORY;
case MA_AUDCLNT_E_OFFLOAD_MODE_ONLY:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_RESOURCES_INVALIDATED:Mr MA_INVALID_DATA;
case MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_HEADTRACKING_ENABLED:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED:Mr MA_INVALID_OPERATION;
case MA_AUDCLNT_S_BUFFER_EMPTY:Mr MA_NO_SPACE;
case MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED:Mr MA_ALREADY_EXISTS;
case MA_AUDCLNT_S_POSITION_STALLED:Mr MA_ERROR;
case MA_DS_NO_VIRTUALIZATION:Mr Ms;
case MA_DSERR_ALLOCATED:Mr MA_ALREADY_IN_USE;
case MA_DSERR_CONTROLUNAVAIL:Mr MA_INVALID_OPERATION;
case MA_DSERR_INVALIDCALL:Mr MA_INVALID_OPERATION;
case MA_DSERR_PRIOLEVELNEEDED:Mr MA_INVALID_OPERATION;
case MA_DSERR_BADFORMAT:Mr MA_FORMAT_NOT_SUPPORTED;
case MA_DSERR_NODRIVER:Mr MA_FAILED_TO_INIT_BACKEND;
case MA_DSERR_ALREADYINITIALIZED:Mr MA_DEVICE_ALREADY_INITIALIZED;
case MA_DSERR_NOAGGREGATION:Mr MA_ERROR;
case MA_DSERR_BUFFERLOST:Mr MA_UNAVAILABLE;
case MA_DSERR_OTHERAPPHASPRIO:Mr MA_ACCESS_DENIED;
case MA_DSERR_UNINITIALIZED:Mr MA_DEVICE_NOT_INITIALIZED;
case MA_DSERR_BUFFERTOOSMALL:Mr MA_NO_SPACE;
case MA_DSERR_DS8_REQUIRED:Mr MA_INVALID_OPERATION;
case MA_DSERR_SENDLOOP:Mr MA_DEADLOCK;
case MA_DSERR_BADSENDBUFFERGUID:Mr MA_INVALID_ARGS;
case MA_DSERR_OBJECTNOTFOUND:Mr MA_NO_DEVICE;
case MA_DSERR_FXUNAVAILABLE:Mr MA_UNAVAILABLE;
default:Mr MA_ERROR;
}
}
#define MA_VT_LPWSTR 31
#define MA_VT_BLOB 65
#if defined(_MSC_VER)&&!defined(__clang__)
#pragma warning(push)
#pragma warning(disable:4201)
#elif defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=8)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc11-extensions"
#endif
#endif
typedef struct
{
WORD vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union
{
struct
{
ULONG cbSize;
BYTE*pBlobData;
} blob;
WCHAR*pwszVal;
char pad[16];
};
} MA_PROPVARIANT;
#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
#endif
typedef HRESULT (WINAPI*MA_PFN_CoInitialize)(Mv*pvReserved);
typedef HRESULT (WINAPI*MA_PFN_CoInitializeEx)(Mv*pvReserved,DWORD dwCoInit);
typedef Mv (WINAPI*MA_PFN_CoUninitialize)(Mv);
typedef HRESULT (WINAPI*MA_PFN_CoCreateInstance)(const IID*rclsid,Mv*pUnkOuter,DWORD dwClsContext,const IID*riid,Mv*ppv);
typedef Mv (WINAPI*MA_PFN_CoTaskMemFree)(Mv*pv);
typedef HRESULT (WINAPI*MA_PFN_PropVariantClear)(MA_PROPVARIANT*pvar);
typedef int (WINAPI*MA_PFN_StringFromGUID2)(const GUID*const rguid,WCHAR*lpsz,int cchMax);
typedef HWND (WINAPI*MA_PFN_GetForegroundWindow)(Mv);
typedef HWND (WINAPI*MA_PFN_GetDesktopWindow)(Mv);
#if defined(MA_WIN32_DESKTOP)
typedef LONG (WINAPI*MA_PFN_RegOpenKeyExA)(HKEY hKey,const char*lpSubKey,DWORD ulOptions,DWORD samDesired,HKEY*phkResult);
typedef LONG (WINAPI*MA_PFN_RegCloseKey)(HKEY hKey);
typedef LONG (WINAPI*MA_PFN_RegQueryValueExA)(HKEY hKey,const char*lpValueName,DWORD*lpReserved,DWORD*lpType,BYTE*lpData,DWORD*lpcbData);
#endif
MA_API size_t ma_strlen_WCHAR(const WCHAR*str)
{
size_t len=0;
while (str[len] !='\0') {
len+=1;
}
Mr len;
}
MA_API int ma_strcmp_WCHAR(const WCHAR*s1,const WCHAR*s2)
{
while (*s1 !='\0'&&*s1==*s2) {
s1+=1;
s2+=1;
}
Mr*s1-*s2;
}
MA_API int ma_strcpy_s_WCHAR(WCHAR*dst,size_t dstCap,const WCHAR*src)
{
size_t i;
if (dst==0) {
Mr 22;
}
if (dstCap==0) {
Mr 34;
}
if (src==0) {
dst[0]='\0';
Mr 22;
}
for (i=0; i<dstCap&&src[i] !='\0';++i) {
dst[i]=src[i];
}
if (i<dstCap) {
dst[i]='\0';
Mr 0;
}
dst[0]='\0';
Mr 34;
}
#endif
#define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device"
#define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device"
#if defined(MA_WIN32)&&!defined(MA_POSIX)
static LARGE_INTEGER g_ma_TimerFrequency;
static Mv 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)) {
Mr 0;
}
Mr (double)(counter.QuadPart-pTimer->counter) / g_ma_TimerFrequency.QuadPart;
}
#elif defined(MA_APPLE)&&(MAC_OS_X_VERSION_MIN_REQUIRED<101200)
static M6 g_ma_TimerFrequency=0;
static Mv 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)
{
M6 newTimeCounter=mach_absolute_time();
M6 oldTimeCounter=pTimer->counter;
Mr (newTimeCounter-oldTimeCounter) / g_ma_TimerFrequency;
}
#elif defined(MA_EMSCRIPTEN)
static MA_INLINE Mv ma_timer_init(ma_timer*pTimer)
{
pTimer->counterD=emscripten_get_now();
}
static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer*pTimer)
{
Mr (emscripten_get_now()-pTimer->counterD) / 1000;
}
#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 Mv 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)
{
M6 newTimeCounter;
M6 oldTimeCounter;
struct timespec newTime;
clock_gettime(MA_CLOCK_ID,&newTime);
newTimeCounter=(newTime.tv_sec*1000000000)+newTime.tv_nsec;
oldTimeCounter=pTimer->counter;
Mr (newTimeCounter-oldTimeCounter) / 1000000000.0;
}
#else
static Mv 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)
{
M6 newTimeCounter;
M6 oldTimeCounter;
struct timeval newTime;
gettimeofday(&newTime,NULL);
newTimeCounter=(newTime.tv_sec*1000000)+newTime.tv_usec;
oldTimeCounter=pTimer->counter;
Mr (newTimeCounter-oldTimeCounter) / 1000000.0;
}
#endif
#endif
#if 0
static M3 ma_get_closest_standard_sample_rate(M3 sampleRateIn)
{
M3 closestRate=0;
M3 closestDiff=0xFFFFFFFF;
size_t iStandardRate;
for (iStandardRate=0; iStandardRate<ma_countof(g_maStandardSampleRatePriorities);++iStandardRate) {
M3 standardRate=g_maStandardSampleRatePriorities[iStandardRate];
M3 diff;
if (sampleRateIn>standardRate) {
diff=sampleRateIn-standardRate;
} else {
diff=standardRate-sampleRateIn;
}
if (diff==0) {
Mr standardRate;
}
if (closestDiff>diff) {
closestDiff=diff;
closestRate=standardRate;
}
}
Mr closestRate;
}
#endif
static MA_INLINE unsigned int ma_device_disable_denormals(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (!Md->noDisableDenormals) {
Mr ma_disable_denormals();
} else {
Mr 0;
}
}
static MA_INLINE Mv ma_device_restore_denormals(ma_device*Md,unsigned int prevState)
{
MA_ASSERT(Md !=NULL);
if (!Md->noDisableDenormals) {
ma_restore_denormals(prevState);
} else {
(Mv)prevState;
}
}
static ma_device_notification ma_device_notification_init(ma_device*Md,ma_device_notification_type type)
{
ma_device_notification notification;
MA_ZERO_OBJECT(&notification);
notification.Md=Md;
notification.type=type;
Mr notification;
}
static Mv ma_device__on_notification(ma_device_notification notification)
{
MA_ASSERT(notification.Md !=NULL);
if (notification.Md->onNotification !=NULL) {
notification.Md->onNotification(&notification);
}
if (notification.Md->onStop !=NULL&&notification.type==ma_device_notification_type_stopped) {
notification.Md->onStop(notification.Md);
}
}
static Mv ma_device__on_notification_started(ma_device*Md)
{
ma_device__on_notification(ma_device_notification_init(Md,ma_device_notification_type_started));
}
static Mv ma_device__on_notification_stopped(ma_device*Md)
{
ma_device__on_notification(ma_device_notification_init(Md,ma_device_notification_type_stopped));
}
#if !defined(MA_EMSCRIPTEN)
static Mv ma_device__on_notification_rerouted(ma_device*Md)
{
ma_device__on_notification(ma_device_notification_init(Md,ma_device_notification_type_rerouted));
}
#endif
#if defined(MA_EMSCRIPTEN)
#ifdef __cplusplus
extern "C" {
#endif
Mv EMSCRIPTEN_KEEPALIVE ma_device__on_notification_unlocked(ma_device*Md)
{
ma_device__on_notification(ma_device_notification_init(Md,ma_device_notification_type_unlocked));
}
#ifdef __cplusplus
}
#endif
#endif
static Mv ma_device__on_data_inner(ma_device*Md,Mv*pFramesOut,const Mv*pFramesIn,M3 frameCount)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(Md->onData !=NULL);
if (!Md->noPreSilencedOutputBuffer&&pFramesOut !=NULL) {
ma_silence_pcm_frames(pFramesOut,frameCount,Md->playback.format,Md->playback.Mh);
}
Md->onData(Md,pFramesOut,pFramesIn,frameCount);
}
static Mv ma_device__on_data(ma_device*Md,Mv*pFramesOut,const Mv*pFramesIn,M3 frameCount)
{
MA_ASSERT(Md !=NULL);
if (ma_device_get_state(Md)==ma_device_state_stopping) {
Mr;
}
if (Md->noFixedSizedCallback) {
ma_device__on_data_inner(Md,pFramesOut,pFramesIn,frameCount);
} else {
M3 totalFramesProcessed=0;
while (totalFramesProcessed<frameCount) {
M3 totalFramesRemaining=frameCount-totalFramesProcessed;
M3 framesToProcessThisIteration=0;
if (pFramesIn !=NULL) {
if (Md->capture.intermediaryBufferLen<Md->capture.intermediaryBufferCap) {
 framesToProcessThisIteration=totalFramesRemaining;
 if (framesToProcessThisIteration>Md->capture.intermediaryBufferCap-Md->capture.intermediaryBufferLen) {
 framesToProcessThisIteration=Md->capture.intermediaryBufferCap-Md->capture.intermediaryBufferLen;
 }
 ma_copy_pcm_frames(
 ma_offset_pcm_frames_ptr(Md->capture.pIntermediaryBuffer,Md->capture.intermediaryBufferLen,Md->capture.format,Md->capture.Mh),ma_offset_pcm_frames_const_ptr(pFramesIn,totalFramesProcessed,Md->capture.format,Md->capture.Mh),framesToProcessThisIteration,Md->capture.format,Md->capture.Mh);
 Md->capture.intermediaryBufferLen+=framesToProcessThisIteration;
}
if (Md->capture.intermediaryBufferLen==Md->capture.intermediaryBufferCap) {
 if (Md->type==ma_device_type_duplex) {
 } else {
 ma_device__on_data_inner(Md,NULL,Md->capture.pIntermediaryBuffer,Md->capture.intermediaryBufferCap);
 Md->capture.intermediaryBufferLen=0;
 }
}
}
if (pFramesOut !=NULL) {
if (Md->playback.intermediaryBufferLen>0) {
 if (Md->type==ma_device_type_duplex) {
 } else {
 framesToProcessThisIteration=totalFramesRemaining;
 if (framesToProcessThisIteration>Md->playback.intermediaryBufferLen) {
 framesToProcessThisIteration=Md->playback.intermediaryBufferLen;
 }
 }
 ma_copy_pcm_frames(
 ma_offset_pcm_frames_ptr(pFramesOut,totalFramesProcessed,Md->playback.format,Md->playback.Mh),ma_offset_pcm_frames_ptr(Md->playback.pIntermediaryBuffer,Md->playback.intermediaryBufferCap-Md->playback.intermediaryBufferLen,Md->playback.format,Md->playback.Mh),framesToProcessThisIteration,Md->playback.format,Md->playback.Mh);
 Md->playback.intermediaryBufferLen-=framesToProcessThisIteration;
}
if (Md->playback.intermediaryBufferLen==0) {
 if (Md->type==ma_device_type_duplex) {
 } else {
 ma_device__on_data_inner(Md,Md->playback.pIntermediaryBuffer,NULL,Md->playback.intermediaryBufferCap);
 Md->playback.intermediaryBufferLen=Md->playback.intermediaryBufferCap;
 }
}
}
if (Md->type==ma_device_type_duplex) {
if (Md->capture.intermediaryBufferLen==Md->capture.intermediaryBufferCap) {
 ma_device__on_data_inner(Md,Md->playback.pIntermediaryBuffer,Md->capture.pIntermediaryBuffer,Md->capture.intermediaryBufferCap);
 Md->playback.intermediaryBufferLen=Md->playback.intermediaryBufferCap;
 Md->capture.intermediaryBufferLen=0;
}
}
totalFramesProcessed+=framesToProcessThisIteration;
}
}
}
static Mv ma_device__handle_data_callback(ma_device*Md,Mv*pFramesOut,const Mv*pFramesIn,M3 frameCount)
{
float masterVolumeFactor;
ma_device_get_master_volume(Md,&masterVolumeFactor);
if (Md->onData) {
unsigned int prevDenormalState=ma_device_disable_denormals(Md);
{
if (pFramesIn !=NULL&&masterVolumeFactor !=1) {
ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M3 bpfCapture=ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh);
M3 bpfPlayback=ma_get_bytes_per_frame(Md->playback.format,Md->playback.Mh);
M3 totalFramesProcessed=0;
while (totalFramesProcessed<frameCount) {
 M3 framesToProcessThisIteration=frameCount-totalFramesProcessed;
 if (framesToProcessThisIteration>sizeof(tempFramesIn)/bpfCapture) {
 framesToProcessThisIteration=sizeof(tempFramesIn)/bpfCapture;
 }
 ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn,ma_offset_ptr(pFramesIn,totalFramesProcessed*bpfCapture),framesToProcessThisIteration,Md->capture.format,Md->capture.Mh,masterVolumeFactor);
 ma_device__on_data(Md,ma_offset_ptr(pFramesOut,totalFramesProcessed*bpfPlayback),tempFramesIn,framesToProcessThisIteration);
 totalFramesProcessed+=framesToProcessThisIteration;
}
} else {
ma_device__on_data(Md,pFramesOut,pFramesIn,frameCount);
}
if (pFramesOut !=NULL) {
if (masterVolumeFactor !=1) {
 if (pFramesIn==NULL) {
 ma_apply_volume_factor_pcm_frames(pFramesOut,frameCount,Md->playback.format,Md->playback.Mh,masterVolumeFactor);
 }
}
if (!Md->noClip&&Md->playback.format==ma_format_f32) {
 ma_clip_samples_f32((float*)pFramesOut,(const float*)pFramesOut,frameCount*Md->playback.Mh);
}
}
}
ma_device_restore_denormals(Md,prevDenormalState);
} else {
if (pFramesOut !=NULL) {
ma_silence_pcm_frames(pFramesOut,frameCount,Md->playback.format,Md->playback.Mh);
}
}
}
static Mv ma_device__read_frames_from_client(ma_device*Md,M3 frameCount,Mv*pFramesOut)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(frameCount>0);
MA_ASSERT(pFramesOut !=NULL);
if (Md->playback.converter.isPassthrough) {
ma_device__handle_data_callback(Md,pFramesOut,NULL,frameCount);
} else {
Me Mf;
M6 totalFramesReadOut;
Mv*pRunningFramesOut;
totalFramesReadOut=0;
pRunningFramesOut=pFramesOut;
if (Md->playback.pInputCache !=NULL) {
while (totalFramesReadOut<frameCount) {
M6 framesToReadThisIterationIn;
M6 framesToReadThisIterationOut;
if (Md->playback.inputCacheRemaining>0) {
 framesToReadThisIterationOut=(frameCount-totalFramesReadOut);
 framesToReadThisIterationIn=framesToReadThisIterationOut;
 if (framesToReadThisIterationIn>Md->playback.inputCacheRemaining) {
 framesToReadThisIterationIn=Md->playback.inputCacheRemaining;
 }
 Mf=ma_data_converter_process_pcm_frames(&Md->playback.converter,ma_offset_pcm_frames_ptr(Md->playback.pInputCache,Md->playback.inputCacheConsumed,Md->playback.format,Md->playback.Mh),&framesToReadThisIterationIn,pRunningFramesOut,&framesToReadThisIterationOut);
 if (Mf !=Ms) {
 break;
 }
 Md->playback.inputCacheConsumed+=framesToReadThisIterationIn;
 Md->playback.inputCacheRemaining-=framesToReadThisIterationIn;
 totalFramesReadOut+=framesToReadThisIterationOut;
 pRunningFramesOut=ma_offset_ptr(pRunningFramesOut,framesToReadThisIterationOut*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
 if (framesToReadThisIterationIn==0&&framesToReadThisIterationOut==0) {
 break;
 }
}
if (Md->playback.inputCacheRemaining==0) {
 ma_device__handle_data_callback(Md,Md->playback.pInputCache,NULL,(M3)Md->playback.inputCacheCap);
 Md->playback.inputCacheConsumed=0;
 Md->playback.inputCacheRemaining=Md->playback.inputCacheCap;
}
}
} else {
while (totalFramesReadOut<frameCount) {
ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 intermediaryBufferCap=sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(Md->playback.format,Md->playback.Mh);
M6 framesToReadThisIterationIn;
M6 framesReadThisIterationIn;
M6 framesToReadThisIterationOut;
M6 framesReadThisIterationOut;
M6 requiredInputFrameCount;
framesToReadThisIterationOut=(frameCount-totalFramesReadOut);
framesToReadThisIterationIn=framesToReadThisIterationOut;
if (framesToReadThisIterationIn>intermediaryBufferCap) {
 framesToReadThisIterationIn=intermediaryBufferCap;
}
ma_data_converter_get_required_input_frame_count(&Md->playback.converter,framesToReadThisIterationOut,&requiredInputFrameCount);
if (framesToReadThisIterationIn>requiredInputFrameCount) {
 framesToReadThisIterationIn=requiredInputFrameCount;
}
ma_device__handle_data_callback(Md,pIntermediaryBuffer,NULL,(M3)framesToReadThisIterationIn);
framesReadThisIterationIn=framesToReadThisIterationIn;
framesReadThisIterationOut=framesToReadThisIterationOut;
Mf=ma_data_converter_process_pcm_frames(&Md->playback.converter,pIntermediaryBuffer,&framesReadThisIterationIn,pRunningFramesOut,&framesReadThisIterationOut);
if (Mf !=Ms) {
 break;
}
totalFramesReadOut+=framesReadThisIterationOut;
pRunningFramesOut=ma_offset_ptr(pRunningFramesOut,framesReadThisIterationOut*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
if (framesReadThisIterationIn==0&&framesReadThisIterationOut==0) {
 break;
}
}
}
}
}
static Mv ma_device__send_frames_to_client(ma_device*Md,M3 frameCountInDeviceFormat,const Mv*pFramesInDeviceFormat)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(frameCountInDeviceFormat>0);
MA_ASSERT(pFramesInDeviceFormat !=NULL);
if (Md->capture.converter.isPassthrough) {
ma_device__handle_data_callback(Md,NULL,pFramesInDeviceFormat,frameCountInDeviceFormat);
} else {
Me Mf;
ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 framesInClientFormatCap=sizeof(pFramesInClientFormat) / ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh);
M6 totalDeviceFramesProcessed=0;
M6 totalClientFramesProcessed=0;
const Mv*pRunningFramesInDeviceFormat=pFramesInDeviceFormat;
for (;;) {
M6 deviceFramesProcessedThisIteration;
M6 clientFramesProcessedThisIteration;
deviceFramesProcessedThisIteration=(frameCountInDeviceFormat-totalDeviceFramesProcessed);
clientFramesProcessedThisIteration=framesInClientFormatCap;
Mf=ma_data_converter_process_pcm_frames(&Md->capture.converter,pRunningFramesInDeviceFormat,&deviceFramesProcessedThisIteration,pFramesInClientFormat,&clientFramesProcessedThisIteration);
if (Mf !=Ms) {
break;
}
if (clientFramesProcessedThisIteration>0) {
ma_device__handle_data_callback(Md,NULL,pFramesInClientFormat,(M3)clientFramesProcessedThisIteration);
}
pRunningFramesInDeviceFormat=ma_offset_ptr(pRunningFramesInDeviceFormat,deviceFramesProcessedThisIteration*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels));
totalDeviceFramesProcessed+=deviceFramesProcessedThisIteration;
totalClientFramesProcessed+=clientFramesProcessedThisIteration;
(Mv)totalClientFramesProcessed;
if (deviceFramesProcessedThisIteration==0&&clientFramesProcessedThisIteration==0) {
break;
}
}
}
}
static Me ma_device__handle_duplex_callback_capture(ma_device*Md,M3 frameCountInDeviceFormat,const Mv*pFramesInDeviceFormat,ma_pcm_rb*pRB)
{
Me Mf;
M3 totalDeviceFramesProcessed=0;
const Mv*pRunningFramesInDeviceFormat=pFramesInDeviceFormat;
MA_ASSERT(Md !=NULL);
MA_ASSERT(frameCountInDeviceFormat>0);
MA_ASSERT(pFramesInDeviceFormat !=NULL);
MA_ASSERT(pRB !=NULL);
for (;;) {
M3 framesToProcessInDeviceFormat=(frameCountInDeviceFormat-totalDeviceFramesProcessed);
M3 framesToProcessInClientFormat=MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh);
M6 framesProcessedInDeviceFormat;
M6 framesProcessedInClientFormat;
Mv*pFramesInClientFormat;
Mf=ma_pcm_rb_acquire_write(pRB,&framesToProcessInClientFormat,&pFramesInClientFormat);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.");
break;
}
if (framesToProcessInClientFormat==0) {
if (ma_pcm_rb_pointer_distance(pRB)==(ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) {
break;
}
}
framesProcessedInDeviceFormat=framesToProcessInDeviceFormat;
framesProcessedInClientFormat=framesToProcessInClientFormat;
Mf=ma_data_converter_process_pcm_frames(&Md->capture.converter,pRunningFramesInDeviceFormat,&framesProcessedInDeviceFormat,pFramesInClientFormat,&framesProcessedInClientFormat);
if (Mf !=Ms) {
break;
}
Mf=ma_pcm_rb_commit_write(pRB,(M3)framesProcessedInClientFormat);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.");
break;
}
pRunningFramesInDeviceFormat=ma_offset_ptr(pRunningFramesInDeviceFormat,framesProcessedInDeviceFormat*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels));
totalDeviceFramesProcessed+=(M3)framesProcessedInDeviceFormat;
if (framesProcessedInClientFormat==0&&framesProcessedInDeviceFormat==0) {
break;
}
}
Mr Ms;
}
static Me ma_device__handle_duplex_callback_playback(ma_device*Md,M3 frameCount,Mv*pFramesInInternalFormat,ma_pcm_rb*pRB)
{
Me Mf;
ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M3 totalFramesReadOut=0;
MA_ASSERT(Md !=NULL);
MA_ASSERT(frameCount>0);
MA_ASSERT(pFramesInInternalFormat !=NULL);
MA_ASSERT(pRB !=NULL);
MA_ASSERT(Md->playback.pInputCache !=NULL);
MA_ZERO_MEMORY(silentInputFrames,sizeof(silentInputFrames));
while (totalFramesReadOut<frameCount&&ma_device_is_started(Md)) {
if (Md->playback.inputCacheRemaining>0) {
M6 framesConvertedIn=Md->playback.inputCacheRemaining;
M6 framesConvertedOut=(frameCount-totalFramesReadOut);
ma_data_converter_process_pcm_frames(&Md->playback.converter,ma_offset_pcm_frames_ptr(Md->playback.pInputCache,Md->playback.inputCacheConsumed,Md->playback.format,Md->playback.Mh),&framesConvertedIn,pFramesInInternalFormat,&framesConvertedOut);
Md->playback.inputCacheConsumed+=framesConvertedIn;
Md->playback.inputCacheRemaining-=framesConvertedIn;
totalFramesReadOut+=(M3)framesConvertedOut;
pFramesInInternalFormat=ma_offset_ptr(pFramesInInternalFormat,framesConvertedOut*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
}
if (totalFramesReadOut<frameCount&&Md->playback.inputCacheRemaining==0) {
M3 inputFrameCount;
Mv*pInputFrames;
inputFrameCount=(M3)Md->playback.inputCacheCap;
Mf=ma_pcm_rb_acquire_read(pRB,&inputFrameCount,&pInputFrames);
if (Mf==Ms) {
if (inputFrameCount>0) {
 ma_device__handle_data_callback(Md,Md->playback.pInputCache,pInputFrames,inputFrameCount);
} else {
 if (ma_pcm_rb_pointer_distance(pRB)==0) {
 break;
 }
}
} else {
inputFrameCount=(M3)ma_min(Md->playback.inputCacheCap,sizeof(silentInputFrames) / ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh));
ma_device__handle_data_callback(Md,Md->playback.pInputCache,silentInputFrames,inputFrameCount);
}
Md->playback.inputCacheConsumed=0;
Md->playback.inputCacheRemaining=inputFrameCount;
Mf=ma_pcm_rb_commit_read(pRB,inputFrameCount);
if (Mf !=Ms) {
Mr Mf;
}
}
}
Mr Ms;
}
static MA_INLINE Mv ma_device__set_state(ma_device*Md,ma_device_state newState)
{
ma_atomic_device_state_set(&Md->state,newState);
}
#if defined(MA_WIN32)
static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM={0x00000001,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};
static GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT={0x00000003,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};
#endif
MA_API M3 ma_get_format_priority_index(ma_format format)
{
M3 i;
for (i=0; i<ma_countof(g_maFormatPriorities);++i) {
if (g_maFormatPriorities[i]==format) {
Mr i;
}
}
Mr (M3)-1;
}
static Me ma_device__post_init_setup(ma_device*Md,ma_device_type deviceType);
static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor*pDeviceDescriptor)
{
if (pDeviceDescriptor==NULL) {
Mr MA_FALSE;
}
if (pDeviceDescriptor->format==ma_format_unknown) {
Mr MA_FALSE;
}
if (pDeviceDescriptor->Mh==0||pDeviceDescriptor->Mh>MA_MAX_CHANNELS) {
Mr MA_FALSE;
}
if (pDeviceDescriptor->sampleRate==0) {
Mr MA_FALSE;
}
Mr MA_TRUE;
}
static Me ma_device_audio_thread__default_read_write(ma_device*Md)
{
Me Mf=Ms;
ma_bool32 exitLoop=MA_FALSE;
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M3 capturedDeviceDataCapInFrames=0;
M3 playbackDeviceDataCapInFrames=0;
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex||Md->type==ma_device_type_loopback) {
if (Md->Mc->callbacks.onDeviceRead==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
capturedDeviceDataCapInFrames=sizeof(capturedDeviceData) / ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
if (Md->Mc->callbacks.onDeviceWrite==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
playbackDeviceDataCapInFrames=sizeof(playbackDeviceData) / ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
}
while (ma_device_get_state(Md)==ma_device_state_started&&!exitLoop) {
switch (Md->type) {
case ma_device_type_duplex:
{
M3 totalCapturedDeviceFramesProcessed=0;
M3 capturedDevicePeriodSizeInFrames=ma_min(Md->capture.internalPeriodSizeInFrames,Md->playback.internalPeriodSizeInFrames);
while (totalCapturedDeviceFramesProcessed<capturedDevicePeriodSizeInFrames) {
 M3 capturedDeviceFramesRemaining;
 M3 capturedDeviceFramesProcessed;
 M3 capturedDeviceFramesToProcess;
 M3 capturedDeviceFramesToTryProcessing=capturedDevicePeriodSizeInFrames-totalCapturedDeviceFramesProcessed;
 if (capturedDeviceFramesToTryProcessing>capturedDeviceDataCapInFrames) {
 capturedDeviceFramesToTryProcessing=capturedDeviceDataCapInFrames;
 }
 Mf=Md->Mc->callbacks.onDeviceRead(Md,capturedDeviceData,capturedDeviceFramesToTryProcessing,&capturedDeviceFramesToProcess);
 if (Mf !=Ms) {
 exitLoop=MA_TRUE;
 break;
 }
 capturedDeviceFramesRemaining=capturedDeviceFramesToProcess;
 capturedDeviceFramesProcessed=0;
 for (;;) {
 ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
 ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
 M3 capturedClientDataCapInFrames=sizeof(capturedClientData) / ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh);
 M3 playbackClientDataCapInFrames=sizeof(playbackClientData) / ma_get_bytes_per_frame(Md->playback.format,Md->playback.Mh);
 M6 capturedClientFramesToProcessThisIteration=ma_min(capturedClientDataCapInFrames,playbackClientDataCapInFrames);
 M6 capturedDeviceFramesToProcessThisIteration=capturedDeviceFramesRemaining;
 ma_uint8*pRunningCapturedDeviceFrames=ma_offset_ptr(capturedDeviceData,capturedDeviceFramesProcessed*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels));
 Mf=ma_data_converter_process_pcm_frames(&Md->capture.converter,pRunningCapturedDeviceFrames,&capturedDeviceFramesToProcessThisIteration,capturedClientData,&capturedClientFramesToProcessThisIteration);
 if (Mf !=Ms) {
 break;
 }
 if (capturedClientFramesToProcessThisIteration==0) {
 break;
 }
 ma_device__handle_data_callback(Md,playbackClientData,capturedClientData,(M3)capturedClientFramesToProcessThisIteration);
 capturedDeviceFramesProcessed+=(M3)capturedDeviceFramesToProcessThisIteration;
 capturedDeviceFramesRemaining-=(M3)capturedDeviceFramesToProcessThisIteration;
 for (;;) {
 M6 convertedClientFrameCount=capturedClientFramesToProcessThisIteration;
 M6 convertedDeviceFrameCount=playbackDeviceDataCapInFrames;
 Mf=ma_data_converter_process_pcm_frames(&Md->playback.converter,playbackClientData,&convertedClientFrameCount,playbackDeviceData,&convertedDeviceFrameCount);
 if (Mf !=Ms) {
 break;
 }
 Mf=Md->Mc->callbacks.onDeviceWrite(Md,playbackDeviceData,(M3)convertedDeviceFrameCount,NULL);
 if (Mf !=Ms) {
 exitLoop=MA_TRUE;
 break;
 }
 capturedClientFramesToProcessThisIteration-=(M3)convertedClientFrameCount;
 if (capturedClientFramesToProcessThisIteration==0) {
 break;
 }
 }
 if (Mf !=Ms) {
 exitLoop=MA_TRUE;
 break;
 }
 }
 if (capturedDeviceFramesProcessed==0) {
 break;
 }
 totalCapturedDeviceFramesProcessed+=capturedDeviceFramesProcessed;
}
} break;
case ma_device_type_capture:
case ma_device_type_loopback:
{
M3 periodSizeInFrames=Md->capture.internalPeriodSizeInFrames;
M3 framesReadThisPeriod=0;
while (framesReadThisPeriod<periodSizeInFrames) {
 M3 framesRemainingInPeriod=periodSizeInFrames-framesReadThisPeriod;
 M3 framesProcessed;
 M3 framesToReadThisIteration=framesRemainingInPeriod;
 if (framesToReadThisIteration>capturedDeviceDataCapInFrames) {
 framesToReadThisIteration=capturedDeviceDataCapInFrames;
 }
 Mf=Md->Mc->callbacks.onDeviceRead(Md,capturedDeviceData,framesToReadThisIteration,&framesProcessed);
 if (Mf !=Ms) {
 exitLoop=MA_TRUE;
 break;
 }
 if (framesProcessed==0) {
 break;
 }
 ma_device__send_frames_to_client(Md,framesProcessed,capturedDeviceData);
 framesReadThisPeriod+=framesProcessed;
}
} break;
case Mt:
{
M3 periodSizeInFrames=Md->playback.internalPeriodSizeInFrames;
M3 framesWrittenThisPeriod=0;
while (framesWrittenThisPeriod<periodSizeInFrames) {
 M3 framesRemainingInPeriod=periodSizeInFrames-framesWrittenThisPeriod;
 M3 framesProcessed;
 M3 framesToWriteThisIteration=framesRemainingInPeriod;
 if (framesToWriteThisIteration>playbackDeviceDataCapInFrames) {
 framesToWriteThisIteration=playbackDeviceDataCapInFrames;
 }
 ma_device__read_frames_from_client(Md,framesToWriteThisIteration,playbackDeviceData);
 Mf=Md->Mc->callbacks.onDeviceWrite(Md,playbackDeviceData,framesToWriteThisIteration,&framesProcessed);
 if (Mf !=Ms) {
 exitLoop=MA_TRUE;
 break;
 }
 if (framesProcessed==0) {
 break;
 }
 framesWrittenThisPeriod+=framesProcessed;
}
} break;
default:break;
}
}
Mr Mf;
}
#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(Mv*pData)
{
ma_device*Md=(ma_device*)pData;
MA_ASSERT(Md !=NULL);
for (;;) {
M3 operation;
ma_event_wait(&Md->null_device.operationEvent);
operation=Md->null_device.operation;
if (operation==MA_DEVICE_OP_START__NULL) {
ma_timer_init(&Md->null_device.timer);
Md->null_device.operationResult=Ms;
ma_event_signal(&Md->null_device.operationCompletionEvent);
ma_semaphore_release(&Md->null_device.operationSemaphore);
continue;
}
if (operation==MA_DEVICE_OP_SUSPEND__NULL) {
Md->null_device.priorRunTime+=ma_timer_get_time_in_seconds(&Md->null_device.timer);
ma_timer_init(&Md->null_device.timer);
Md->null_device.operationResult=Ms;
ma_event_signal(&Md->null_device.operationCompletionEvent);
ma_semaphore_release(&Md->null_device.operationSemaphore);
continue;
}
if (operation==MA_DEVICE_OP_KILL__NULL) {
Md->null_device.operationResult=Ms;
ma_event_signal(&Md->null_device.operationCompletionEvent);
ma_semaphore_release(&Md->null_device.operationSemaphore);
break;
}
if (operation==MA_DEVICE_OP_NONE__NULL) {
MA_ASSERT(MA_FALSE);
Md->null_device.operationResult=MA_INVALID_OPERATION;
ma_event_signal(&Md->null_device.operationCompletionEvent);
ma_semaphore_release(&Md->null_device.operationSemaphore);
continue;
}
}
Mr (ma_thread_result)0;
}
static Me ma_device_do_operation__null(ma_device*Md,M3 operation)
{
Me Mf;
Mf=ma_semaphore_wait(&Md->null_device.operationSemaphore);
if (Mf !=Ms) {
Mr Mf;
}
Md->null_device.operation=operation;
if (ma_event_signal(&Md->null_device.operationEvent) !=Ms) {
Mr MA_ERROR;
}
if (ma_event_wait(&Md->null_device.operationCompletionEvent) !=Ms) {
Mr MA_ERROR;
}
Mr Md->null_device.operationResult;
}
static M6 ma_device_get_total_run_time_in_frames__null(ma_device*Md)
{
M3 internalSampleRate;
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
internalSampleRate=Md->capture.internalSampleRate;
} else {
internalSampleRate=Md->playback.internalSampleRate;
}
Mr (M6)((Md->null_device.priorRunTime+ma_timer_get_time_in_seconds(&Md->null_device.timer))*internalSampleRate);
}
static Me ma_context_enumerate_devices__null(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_bool32 cbResult=MA_TRUE;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
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;
cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
}
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;
cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
(Mv)cbResult;
Mr Ms;
}
static Me ma_context_get_device_info__null(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
MA_ASSERT(Mc !=NULL);
if (pDeviceID !=NULL&&pDeviceID->nullbackend !=0) {
Mr MA_NO_DEVICE;
}
if (deviceType==Mt) {
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;
pDeviceInfo->nativeDataFormats[0].format=ma_format_unknown;
pDeviceInfo->nativeDataFormats[0].Mh=0;
pDeviceInfo->nativeDataFormats[0].sampleRate=0;
pDeviceInfo->nativeDataFormats[0].flags=0;
pDeviceInfo->nativeDataFormatCount=1;
(Mv)Mc;
Mr Ms;
}
static Me ma_device_uninit__null(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
ma_device_do_operation__null(Md,MA_DEVICE_OP_KILL__NULL);
ma_thread_wait(&Md->null_device.deviceThread);
ma_semaphore_uninit(&Md->null_device.operationSemaphore);
ma_event_uninit(&Md->null_device.operationCompletionEvent);
ma_event_uninit(&Md->null_device.operationEvent);
Mr Ms;
}
static Me ma_device_init__null(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->null_device);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
pDescriptorCapture->format=(pDescriptorCapture->format !=ma_format_unknown)?pDescriptorCapture->format:MA_DEFAULT_FORMAT;
pDescriptorCapture->Mh=(pDescriptorCapture->Mh !=0)?pDescriptorCapture->Mh: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->Mh);
}
pDescriptorCapture->periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture,pDescriptorCapture->sampleRate,Mo->performanceProfile);
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Mp->format=(Mp->format !=ma_format_unknown)?Mp->format:MA_DEFAULT_FORMAT;
Mp->Mh=(Mp->Mh !=0)?Mp->Mh:MA_DEFAULT_CHANNELS;
Mp->sampleRate=(Mp->sampleRate !=0)?Mp->sampleRate:MA_DEFAULT_SAMPLE_RATE;
if (Mp->channelMap[0]==MA_CHANNEL_NONE) {
ma_channel_map_init_standard(ma_standard_channel_map_default,Mp->channelMap,ma_countof(pDescriptorCapture->channelMap),Mp->Mh);
}
Mp->periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(Mp,Mp->sampleRate,Mo->performanceProfile);
}
Mf=ma_event_init(&Md->null_device.operationEvent);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_event_init(&Md->null_device.operationCompletionEvent);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_semaphore_init(1,&Md->null_device.operationSemaphore);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_thread_create(&Md->null_device.deviceThread,Md->Mc->threadPriority,0,ma_device_thread__null,Md,&Md->Mc->allocationCallbacks);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static Me ma_device_start__null(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
ma_device_do_operation__null(Md,MA_DEVICE_OP_START__NULL);
ma_atomic_bool32_set(&Md->null_device.isStarted,MA_TRUE);
Mr Ms;
}
static Me ma_device_stop__null(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
ma_device_do_operation__null(Md,MA_DEVICE_OP_SUSPEND__NULL);
ma_atomic_bool32_set(&Md->null_device.isStarted,MA_FALSE);
Mr Ms;
}
static ma_bool32 ma_device_is_started__null(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
Mr ma_atomic_bool32_get(&Md->null_device.isStarted);
}
static Me ma_device_write__null(ma_device*Md,const Mv*pPCMFrames,M3 frameCount,M3*pFramesWritten)
{
Me Mf=Ms;
M3 totalPCMFramesProcessed;
ma_bool32 wasStartedOnEntry;
if (pFramesWritten !=NULL) {
*pFramesWritten=0;
}
wasStartedOnEntry=ma_device_is_started__null(Md);
totalPCMFramesProcessed=0;
while (totalPCMFramesProcessed<frameCount) {
M6 targetFrame;
if (Md->null_device.currentPeriodFramesRemainingPlayback>0) {
M3 framesRemaining=(frameCount-totalPCMFramesProcessed);
M3 framesToProcess=Md->null_device.currentPeriodFramesRemainingPlayback;
if (framesToProcess>framesRemaining) {
framesToProcess=framesRemaining;
}
(Mv)pPCMFrames;
Md->null_device.currentPeriodFramesRemainingPlayback-=framesToProcess;
totalPCMFramesProcessed+=framesToProcess;
}
if (Md->null_device.currentPeriodFramesRemainingPlayback==0) {
Md->null_device.currentPeriodFramesRemainingPlayback=0;
if (!ma_device_is_started__null(Md)&&!wasStartedOnEntry) {
Mf=ma_device_start__null(Md);
if (Mf !=Ms) {
 break;
}
}
}
MA_ASSERT(totalPCMFramesProcessed<=frameCount);
if (totalPCMFramesProcessed==frameCount) {
break;
}
targetFrame=Md->null_device.lastProcessedFramePlayback;
for (;;) {
M6 currentFrame;
if (!ma_device_is_started__null(Md)) {
break;
}
currentFrame=ma_device_get_total_run_time_in_frames__null(Md);
if (currentFrame>=targetFrame) {
break;
}
ma_sleep(10);
}
Md->null_device.lastProcessedFramePlayback+=Md->playback.internalPeriodSizeInFrames;
Md->null_device.currentPeriodFramesRemainingPlayback=Md->playback.internalPeriodSizeInFrames;
}
if (pFramesWritten !=NULL) {
*pFramesWritten=totalPCMFramesProcessed;
}
Mr Mf;
}
static Me ma_device_read__null(ma_device*Md,Mv*pPCMFrames,M3 frameCount,M3*pFramesRead)
{
Me Mf=Ms;
M3 totalPCMFramesProcessed;
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
totalPCMFramesProcessed=0;
while (totalPCMFramesProcessed<frameCount) {
M6 targetFrame;
if (Md->null_device.currentPeriodFramesRemainingCapture>0) {
M3 bpf=ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
M3 framesRemaining=(frameCount-totalPCMFramesProcessed);
M3 framesToProcess=Md->null_device.currentPeriodFramesRemainingCapture;
if (framesToProcess>framesRemaining) {
framesToProcess=framesRemaining;
}
MA_ZERO_MEMORY(ma_offset_ptr(pPCMFrames,totalPCMFramesProcessed*bpf),framesToProcess*bpf);
Md->null_device.currentPeriodFramesRemainingCapture-=framesToProcess;
totalPCMFramesProcessed+=framesToProcess;
}
if (Md->null_device.currentPeriodFramesRemainingCapture==0) {
Md->null_device.currentPeriodFramesRemainingCapture=0;
}
MA_ASSERT(totalPCMFramesProcessed<=frameCount);
if (totalPCMFramesProcessed==frameCount) {
break;
}
targetFrame=Md->null_device.lastProcessedFrameCapture+Md->capture.internalPeriodSizeInFrames;
for (;;) {
M6 currentFrame;
if (!ma_device_is_started__null(Md)) {
break;
}
currentFrame=ma_device_get_total_run_time_in_frames__null(Md);
if (currentFrame>=targetFrame) {
break;
}
ma_sleep(10);
}
Md->null_device.lastProcessedFrameCapture+=Md->capture.internalPeriodSizeInFrames;
Md->null_device.currentPeriodFramesRemainingCapture=Md->capture.internalPeriodSizeInFrames;
}
if (pFramesRead !=NULL) {
*pFramesRead=totalPCMFramesProcessed;
}
Mr Mf;
}
static Me ma_context_uninit__null(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_null);
(Mv)Mc;
Mr Ms;
}
static Me ma_context_init__null(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
(Mv)Mc;
pCallbacks->onContextInit=ma_context_init__null;
pCallbacks->onContextUninit=ma_context_uninit__null;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__null;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__null;
pCallbacks->onDeviceInit=ma_device_init__null;
pCallbacks->onDeviceUninit=ma_device_uninit__null;
pCallbacks->onDeviceStart=ma_device_start__null;
pCallbacks->onDeviceStop=ma_device_stop__null;
pCallbacks->onDeviceRead=ma_device_read__null;
pCallbacks->onDeviceWrite=ma_device_write__null;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#if defined(MA_WIN32)
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
#define ma_CoInitializeEx(Mc,pvReserved,dwCoInit) ((Mc->win32.CoInitializeEx)?((MA_PFN_CoInitializeEx)Mc->win32.CoInitializeEx)(pvReserved,dwCoInit):((MA_PFN_CoInitialize)Mc->win32.CoInitialize)(pvReserved))
#define ma_CoUninitialize(Mc) ((MA_PFN_CoUninitialize)Mc->win32.CoUninitialize)()
#define ma_CoCreateInstance(Mc,rclsid,pUnkOuter,dwClsContext,riid,ppv) ((MA_PFN_CoCreateInstance)Mc->win32.CoCreateInstance)(rclsid,pUnkOuter,dwClsContext,riid,ppv)
#define ma_CoTaskMemFree(Mc,pv) ((MA_PFN_CoTaskMemFree)Mc->win32.CoTaskMemFree)(pv)
#define ma_PropVariantClear(Mc,pvar) ((MA_PFN_PropVariantClear)Mc->win32.PropVariantClear)(pvar)
#else
#define ma_CoInitializeEx(Mc,pvReserved,dwCoInit) CoInitializeEx(pvReserved,dwCoInit)
#define ma_CoUninitialize(Mc) CoUninitialize()
#define ma_CoCreateInstance(Mc,rclsid,pUnkOuter,dwClsContext,riid,ppv) CoCreateInstance(rclsid,pUnkOuter,dwClsContext,riid,ppv)
#define ma_CoTaskMemFree(Mc,pv) CoTaskMemFree(pv)
#define ma_PropVariantClear(Mc,pvar) PropVariantClear(pvar)
#endif
#if !defined(MAXULONG_PTR)&&!defined(__WATCOMC__)
typedef size_t DWORD_PTR;
#endif
#if !defined(WAVE_FORMAT_1M08)
#define WAVE_FORMAT_1M08 0x00000001
#define WAVE_FORMAT_1S08 0x00000002
#define WAVE_FORMAT_1M16 0x00000004
#define WAVE_FORMAT_1S16 0x00000008
#define WAVE_FORMAT_2M08 0x00000010
#define WAVE_FORMAT_2S08 0x00000020
#define WAVE_FORMAT_2M16 0x00000040
#define WAVE_FORMAT_2S16 0x00000080
#define WAVE_FORMAT_4M08 0x00000100
#define WAVE_FORMAT_4S08 0x00000200
#define WAVE_FORMAT_4M16 0x00000400
#define WAVE_FORMAT_4S16 0x00000800
#endif
#if !defined(WAVE_FORMAT_44M08)
#define WAVE_FORMAT_44M08 0x00000100
#define WAVE_FORMAT_44S08 0x00000200
#define WAVE_FORMAT_44M16 0x00000400
#define WAVE_FORMAT_44S16 0x00000800
#define WAVE_FORMAT_48M08 0x00001000
#define WAVE_FORMAT_48S08 0x00002000
#define WAVE_FORMAT_48M16 0x00004000
#define WAVE_FORMAT_48S16 0x00008000
#define WAVE_FORMAT_96M08 0x00010000
#define WAVE_FORMAT_96S08 0x00020000
#define WAVE_FORMAT_96M16 0x00040000
#define WAVE_FORMAT_96S16 0x00080000
#endif
#ifndef SPEAKER_FRONT_LEFT
#define SPEAKER_FRONT_LEFT 0x1
#define SPEAKER_FRONT_RIGHT 0x2
#define SPEAKER_FRONT_CENTER 0x4
#define SPEAKER_LOW_FREQUENCY 0x8
#define SPEAKER_BACK_LEFT 0x10
#define SPEAKER_BACK_RIGHT 0x20
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
#define SPEAKER_BACK_CENTER 0x100
#define SPEAKER_SIDE_LEFT 0x200
#define SPEAKER_SIDE_RIGHT 0x400
#define SPEAKER_TOP_CENTER 0x800
#define SPEAKER_TOP_FRONT_LEFT 0x1000
#define SPEAKER_TOP_FRONT_CENTER 0x2000
#define SPEAKER_TOP_FRONT_RIGHT 0x4000
#define SPEAKER_TOP_BACK_LEFT 0x8000
#define SPEAKER_TOP_BACK_CENTER 0x10000
#define SPEAKER_TOP_BACK_RIGHT 0x20000
#endif
typedef struct
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} MA_WAVEFORMATEX;
typedef struct
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
union
{
WORD wValidBitsPerSample;
WORD wSamplesPerBlock;
WORD wReserved;
} Samples;
DWORD dwChannelMask;
GUID SubFormat;
} MA_WAVEFORMATEXTENSIBLE;
#ifndef WAVE_FORMAT_EXTENSIBLE
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
#ifndef WAVE_FORMAT_PCM
#define WAVE_FORMAT_PCM 1
#endif
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
static ma_uint8 ma_channel_id_to_ma__win32(DWORD id)
{
switch (id)
{
case SPEAKER_FRONT_LEFT:Mr MA_CHANNEL_FRONT_LEFT;
case SPEAKER_FRONT_RIGHT:Mr MA_CHANNEL_FRONT_RIGHT;
case SPEAKER_FRONT_CENTER:Mr MA_CHANNEL_FRONT_CENTER;
case SPEAKER_LOW_FREQUENCY:Mr MA_CHANNEL_LFE;
case SPEAKER_BACK_LEFT:Mr MA_CHANNEL_BACK_LEFT;
case SPEAKER_BACK_RIGHT:Mr MA_CHANNEL_BACK_RIGHT;
case SPEAKER_FRONT_LEFT_OF_CENTER:Mr MA_CHANNEL_FRONT_LEFT_CENTER;
case SPEAKER_FRONT_RIGHT_OF_CENTER:Mr MA_CHANNEL_FRONT_RIGHT_CENTER;
case SPEAKER_BACK_CENTER:Mr MA_CHANNEL_BACK_CENTER;
case SPEAKER_SIDE_LEFT:Mr MA_CHANNEL_SIDE_LEFT;
case SPEAKER_SIDE_RIGHT:Mr MA_CHANNEL_SIDE_RIGHT;
case SPEAKER_TOP_CENTER:Mr MA_CHANNEL_TOP_CENTER;
case SPEAKER_TOP_FRONT_LEFT:Mr MA_CHANNEL_TOP_FRONT_LEFT;
case SPEAKER_TOP_FRONT_CENTER:Mr MA_CHANNEL_TOP_FRONT_CENTER;
case SPEAKER_TOP_FRONT_RIGHT:Mr MA_CHANNEL_TOP_FRONT_RIGHT;
case SPEAKER_TOP_BACK_LEFT:Mr MA_CHANNEL_TOP_BACK_LEFT;
case SPEAKER_TOP_BACK_CENTER:Mr MA_CHANNEL_TOP_BACK_CENTER;
case SPEAKER_TOP_BACK_RIGHT:Mr MA_CHANNEL_TOP_BACK_RIGHT;
default:Mr 0;
}
}
static DWORD ma_channel_id_to_win32(DWORD id)
{
switch (id)
{
case MA_CHANNEL_MONO:Mr SPEAKER_FRONT_CENTER;
case MA_CHANNEL_FRONT_LEFT:Mr SPEAKER_FRONT_LEFT;
case MA_CHANNEL_FRONT_RIGHT:Mr SPEAKER_FRONT_RIGHT;
case MA_CHANNEL_FRONT_CENTER:Mr SPEAKER_FRONT_CENTER;
case MA_CHANNEL_LFE:Mr SPEAKER_LOW_FREQUENCY;
case MA_CHANNEL_BACK_LEFT:Mr SPEAKER_BACK_LEFT;
case MA_CHANNEL_BACK_RIGHT:Mr SPEAKER_BACK_RIGHT;
case MA_CHANNEL_FRONT_LEFT_CENTER:Mr SPEAKER_FRONT_LEFT_OF_CENTER;
case MA_CHANNEL_FRONT_RIGHT_CENTER:Mr SPEAKER_FRONT_RIGHT_OF_CENTER;
case MA_CHANNEL_BACK_CENTER:Mr SPEAKER_BACK_CENTER;
case MA_CHANNEL_SIDE_LEFT:Mr SPEAKER_SIDE_LEFT;
case MA_CHANNEL_SIDE_RIGHT:Mr SPEAKER_SIDE_RIGHT;
case MA_CHANNEL_TOP_CENTER:Mr SPEAKER_TOP_CENTER;
case MA_CHANNEL_TOP_FRONT_LEFT:Mr SPEAKER_TOP_FRONT_LEFT;
case MA_CHANNEL_TOP_FRONT_CENTER:Mr SPEAKER_TOP_FRONT_CENTER;
case MA_CHANNEL_TOP_FRONT_RIGHT:Mr SPEAKER_TOP_FRONT_RIGHT;
case MA_CHANNEL_TOP_BACK_LEFT:Mr SPEAKER_TOP_BACK_LEFT;
case MA_CHANNEL_TOP_BACK_CENTER:Mr SPEAKER_TOP_BACK_CENTER;
case MA_CHANNEL_TOP_BACK_RIGHT:Mr SPEAKER_TOP_BACK_RIGHT;
default:Mr 0;
}
}
static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel*pChannelMap,M3 Mh)
{
DWORD dwChannelMask=0;
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
dwChannelMask|=ma_channel_id_to_win32(pChannelMap[iChannel]);
}
Mr dwChannelMask;
}
static Mv ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask,M3 Mh,ma_channel*pChannelMap)
{
if (dwChannelMask==0) {
ma_channel_map_init_standard(ma_standard_channel_map_microsoft,pChannelMap,Mh,Mh);
} else {
if (Mh==1&&(dwChannelMask&SPEAKER_FRONT_CENTER) !=0) {
pChannelMap[0]=MA_CHANNEL_MONO;
} else {
M3 iChannel=0;
M3 iBit;
for (iBit=0; iBit<32&&iChannel<Mh;++iBit) {
DWORD bitValue=(dwChannelMask&(1UL<<iBit));
if (bitValue !=0) {
 pChannelMap[iChannel]=ma_channel_id_to_ma__win32(bitValue);
 iChannel+=1;
}
}
}
}
}
#ifdef __cplusplus
static ma_bool32 ma_is_guid_equal(const Mv*a,const Mv*b)
{
Mr IsEqualGUID(*(const GUID*)a,*(const GUID*)b);
}
#else
#define ma_is_guid_equal(a,b) IsEqualGUID((const GUID*)a,(const GUID*)b)
#endif
static MA_INLINE ma_bool32 ma_is_guid_null(const Mv*guid)
{
static GUID nullguid={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
Mr ma_is_guid_equal(guid,&nullguid);
}
static ma_format ma_format_from_WAVEFORMATEX(const MA_WAVEFORMATEX*pWF)
{
MA_ASSERT(pWF !=NULL);
if (pWF->wFormatTag==WAVE_FORMAT_EXTENSIBLE) {
const MA_WAVEFORMATEXTENSIBLE*pWFEX=(const MA_WAVEFORMATEXTENSIBLE*)pWF;
if (ma_is_guid_equal(&pWFEX->SubFormat,&MA_GUID_KSDATAFORMAT_SUBTYPE_PCM)) {
if (pWFEX->Samples.wValidBitsPerSample==32) {
Mr ma_format_s32;
}
if (pWFEX->Samples.wValidBitsPerSample==24) {
if (pWFEX->wBitsPerSample==32) {
 Mr ma_format_s32;
}
if (pWFEX->wBitsPerSample==24) {
 Mr ma_format_s24;
}
}
if (pWFEX->Samples.wValidBitsPerSample==16) {
Mr ma_format_s16;
}
if (pWFEX->Samples.wValidBitsPerSample==8) {
Mr ma_format_u8;
}
}
if (ma_is_guid_equal(&pWFEX->SubFormat,&MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
if (pWFEX->Samples.wValidBitsPerSample==32) {
Mr ma_format_f32;
}
}
} else {
if (pWF->wFormatTag==WAVE_FORMAT_PCM) {
if (pWF->wBitsPerSample==32) {
Mr ma_format_s32;
}
if (pWF->wBitsPerSample==24) {
Mr ma_format_s24;
}
if (pWF->wBitsPerSample==16) {
Mr ma_format_s16;
}
if (pWF->wBitsPerSample==8) {
Mr ma_format_u8;
}
}
if (pWF->wFormatTag==WAVE_FORMAT_IEEE_FLOAT) {
if (pWF->wBitsPerSample==32) {
Mr ma_format_f32;
}
if (pWF->wBitsPerSample==64) {
}
}
}
Mr ma_format_unknown;
}
#endif
#ifdef MA_HAS_WASAPI
#if 0
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4091)
#endif
#include <audioclient.h>
#include <mmdeviceapi.h>
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif
static Me ma_device_reroute__wasapi(ma_device*Md,ma_device_type deviceType);
#define MA_WIN32_WINNT_VISTA 0x0600
#define MA_VER_MINORVERSION 0x01
#define MA_VER_MAJORVERSION 0x02
#define MA_VER_SERVICEPACKMAJOR 0x20
#define MA_VER_GREATER_EQUAL 0x03
typedef struct {
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
WCHAR szCSDVersion[128];
WORD wServicePackMajor;
WORD wServicePackMinor;
WORD wSuiteMask;
BYTE wProductType;
BYTE wReserved;
} ma_OSVERSIONINFOEXW;
typedef BOOL (WINAPI*ma_PFNVerifyVersionInfoW) (ma_OSVERSIONINFOEXW*lpVersionInfo,DWORD dwTypeMask,DWORDLONG dwlConditionMask);
typedef ULONGLONG (WINAPI*ma_PFNVerSetConditionMask)(ULONGLONG dwlConditionMask,DWORD dwTypeBitMask,BYTE dwConditionMask);
#ifndef PROPERTYKEY_DEFINED
#define PROPERTYKEY_DEFINED
#ifndef __WATCOMC__
typedef struct
{
GUID fmtid;
DWORD pid;
} PROPERTYKEY;
#endif
#endif
static MA_INLINE Mv ma_PropVariantInit(MA_PROPVARIANT*pProp)
{
MA_ZERO_OBJECT(pProp);
}
static const PROPERTYKEY MA_PKEY_Device_FriendlyName={{0xA45C254E,0xDF1C,0x4EFD,{0x80,0x20,0x67,0xD1,0x46,0xA8,0x50,0xE0}},14};
static const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat={{0xF19F064D,0x82C,0x4E27,{0xBC,0x73,0x68,0x82,0xA1,0xBB,0x8E,0x4C}},0};
static const IID MA_IID_IUnknown={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
#if !defined(MA_WIN32_DESKTOP)&&!defined(MA_WIN32_GDK)
static const IID MA_IID_IAgileObject={0x94EA2B94,0xE9CC,0x49E0,{0xC0,0xFF,0xEE,0x64,0xCA,0x8F,0x5B,0x90}};
#endif
static const IID MA_IID_IAudioClient={0x1CB9AD4C,0xDBFA,0x4C32,{0xB1,0x78,0xC2,0xF5,0x68,0xA7,0x03,0xB2}};
static const IID MA_IID_IAudioClient2={0x726778CD,0xF60A,0x4EDA,{0x82,0xDE,0xE4,0x76,0x10,0xCD,0x78,0xAA}};
static const IID MA_IID_IAudioClient3={0x7ED4EE07,0x8E67,0x4CD4,{0x8C,0x1A,0x2B,0x7A,0x59,0x87,0xAD,0x42}};
static const IID MA_IID_IAudioRenderClient={0xF294ACFC,0x3146,0x4483,{0xA7,0xBF,0xAD,0xDC,0xA7,0xC2,0x60,0xE2}};
static const IID MA_IID_IAudioCaptureClient={0xC8ADBD64,0xE71E,0x48A0,{0xA4,0xDE,0x18,0x5C,0x39,0x5C,0xD3,0x17}};
static const IID MA_IID_IMMNotificationClient={0x7991EEC9,0x7E89,0x4D85,{0x83,0x90,0x6C,0x70,0x3C,0xEC,0x60,0xC0}};
#if !defined(MA_WIN32_DESKTOP)&&!defined(MA_WIN32_GDK)
static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER={0xE6327CAD,0xDCEC,0x4949,{0xAE,0x8A,0x99,0x1E,0x97,0x6A,0x79,0xD2}};
static const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE={0x2EEF81BE,0x33FA,0x4800,{0x96,0x70,0x1C,0xD4,0x74,0x97,0x2C,0x3F}};
static const IID MA_IID_IActivateAudioInterfaceCompletionHandler={0x41D949AB,0x9862,0x444A,{0x80,0xF6,0xC2,0x61,0x33,0x4D,0xA5,0xEB}};
#endif
static const IID MA_CLSID_MMDeviceEnumerator={0xBCDE0395,0xE52F,0x467C,{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}};
static const IID MA_IID_IMMDeviceEnumerator={0xA95664D2,0x9614,0x4F35,{0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}};
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
#define MA_MM_DEVICE_STATE_ACTIVE 1
#define MA_MM_DEVICE_STATE_DISABLED 2
#define MA_MM_DEVICE_STATE_NOTPRESENT 4
#define MA_MM_DEVICE_STATE_UNPLUGGED 8
typedef struct ma_IMMDeviceEnumerator ma_IMMDeviceEnumerator;
typedef struct ma_IMMDeviceCollection ma_IMMDeviceCollection;
typedef struct ma_IMMDevice ma_IMMDevice;
#else
typedef struct ma_IActivateAudioInterfaceCompletionHandler ma_IActivateAudioInterfaceCompletionHandler;
typedef struct ma_IActivateAudioInterfaceAsyncOperation ma_IActivateAudioInterfaceAsyncOperation;
#endif
typedef struct ma_IPropertyStore ma_IPropertyStore;
typedef struct ma_IAudioClient ma_IAudioClient;
typedef struct ma_IAudioClient2 ma_IAudioClient2;
typedef struct ma_IAudioClient3 ma_IAudioClient3;
typedef struct ma_IAudioRenderClient ma_IAudioRenderClient;
typedef struct ma_IAudioCaptureClient ma_IAudioCaptureClient;
typedef ma_int64 MA_REFERENCE_TIME;
#define MA_AUDCLNT_STREAMFLAGS_CROSSPROCESS 0x00010000
#define MA_AUDCLNT_STREAMFLAGS_LOOPBACK 0x00020000
#define MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK 0x00040000
#define MA_AUDCLNT_STREAMFLAGS_NOPERSIST 0x00080000
#define MA_AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000
#define MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#define MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#define MA_AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED 0x10000000
#define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE 0x20000000
#define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED 0x40000000
#define MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY 1
#define MA_AUDCLNT_BUFFERFLAGS_SILENT 2
#define MA_AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR 4
typedef enum
{
ma_eRender=0,ma_eCapture=1,ma_eAll=2
} ma_EDataFlow;
typedef enum
{
ma_eConsole=0,ma_eMultimedia=1,ma_eCommunications=2
} ma_ERole;
typedef enum
{
MA_AUDCLNT_SHAREMODE_SHARED,MA_AUDCLNT_SHAREMODE_EXCLUSIVE
} MA_AUDCLNT_SHAREMODE;
typedef enum
{
MA_AudioCategory_Other=0
} MA_AUDIO_STREAM_CATEGORY;
typedef struct
{
M3 cbSize;
BOOL bIsOffload;
MA_AUDIO_STREAM_CATEGORY eCategory;
} ma_AudioClientProperties;
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IUnknown*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IUnknown*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IUnknown*pThis);
} ma_IUnknownVtbl;
struct ma_IUnknown
{
ma_IUnknownVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IUnknown_AddRef(ma_IUnknown*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown*pThis) { Mr pThis->lpVtbl->Release(pThis); }
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IMMNotificationClient*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IMMNotificationClient*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IMMNotificationClient*pThis);
HRESULT (STDMETHODCALLTYPE*OnDeviceStateChanged) (ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID,DWORD dwNewState);
HRESULT (STDMETHODCALLTYPE*OnDeviceAdded) (ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID);
HRESULT (STDMETHODCALLTYPE*OnDeviceRemoved) (ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID);
HRESULT (STDMETHODCALLTYPE*OnDefaultDeviceChanged)(ma_IMMNotificationClient*pThis,ma_EDataFlow dataFlow,ma_ERole role,const WCHAR*pDefaultDeviceID);
HRESULT (STDMETHODCALLTYPE*OnPropertyValueChanged)(ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID,const PROPERTYKEY key);
} ma_IMMNotificationClientVtbl;
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IMMDeviceEnumerator*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IMMDeviceEnumerator*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IMMDeviceEnumerator*pThis);
HRESULT (STDMETHODCALLTYPE*EnumAudioEndpoints) (ma_IMMDeviceEnumerator*pThis,ma_EDataFlow dataFlow,DWORD dwStateMask,ma_IMMDeviceCollection**ppDevices);
HRESULT (STDMETHODCALLTYPE*GetDefaultAudioEndpoint) (ma_IMMDeviceEnumerator*pThis,ma_EDataFlow dataFlow,ma_ERole role,ma_IMMDevice**ppEndpoint);
HRESULT (STDMETHODCALLTYPE*GetDevice) (ma_IMMDeviceEnumerator*pThis,const WCHAR*pID,ma_IMMDevice**ppDevice);
HRESULT (STDMETHODCALLTYPE*RegisterEndpointNotificationCallback) (ma_IMMDeviceEnumerator*pThis,ma_IMMNotificationClient*pClient);
HRESULT (STDMETHODCALLTYPE*UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator*pThis,ma_IMMNotificationClient*pClient);
} ma_IMMDeviceEnumeratorVtbl;
struct ma_IMMDeviceEnumerator
{
ma_IMMDeviceEnumeratorVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IMMDeviceEnumerator_QueryInterface(ma_IMMDeviceEnumerator*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IMMDeviceEnumerator_AddRef(ma_IMMDeviceEnumerator*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IMMDeviceEnumerator_Release(ma_IMMDeviceEnumerator*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IMMDeviceEnumerator_EnumAudioEndpoints(ma_IMMDeviceEnumerator*pThis,ma_EDataFlow dataFlow,DWORD dwStateMask,ma_IMMDeviceCollection**ppDevices) { Mr pThis->lpVtbl->EnumAudioEndpoints(pThis,dataFlow,dwStateMask,ppDevices); }
static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(ma_IMMDeviceEnumerator*pThis,ma_EDataFlow dataFlow,ma_ERole role,ma_IMMDevice**ppEndpoint) { Mr pThis->lpVtbl->GetDefaultAudioEndpoint(pThis,dataFlow,role,ppEndpoint); }
static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator*pThis,const WCHAR*pID,ma_IMMDevice**ppDevice) { Mr pThis->lpVtbl->GetDevice(pThis,pID,ppDevice); }
static MA_INLINE HRESULT ma_IMMDeviceEnumerator_RegisterEndpointNotificationCallback(ma_IMMDeviceEnumerator*pThis,ma_IMMNotificationClient*pClient) { Mr pThis->lpVtbl->RegisterEndpointNotificationCallback(pThis,pClient); }
static MA_INLINE HRESULT ma_IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(ma_IMMDeviceEnumerator*pThis,ma_IMMNotificationClient*pClient) { Mr pThis->lpVtbl->UnregisterEndpointNotificationCallback(pThis,pClient); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IMMDeviceCollection*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IMMDeviceCollection*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IMMDeviceCollection*pThis);
HRESULT (STDMETHODCALLTYPE*GetCount)(ma_IMMDeviceCollection*pThis,UINT*pDevices);
HRESULT (STDMETHODCALLTYPE*Item) (ma_IMMDeviceCollection*pThis,UINT nDevice,ma_IMMDevice**ppDevice);
} ma_IMMDeviceCollectionVtbl;
struct ma_IMMDeviceCollection
{
ma_IMMDeviceCollectionVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IMMDeviceCollection_QueryInterface(ma_IMMDeviceCollection*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IMMDeviceCollection_AddRef(ma_IMMDeviceCollection*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IMMDeviceCollection_Release(ma_IMMDeviceCollection*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IMMDeviceCollection_GetCount(ma_IMMDeviceCollection*pThis,UINT*pDevices) { Mr pThis->lpVtbl->GetCount(pThis,pDevices); }
static MA_INLINE HRESULT ma_IMMDeviceCollection_Item(ma_IMMDeviceCollection*pThis,UINT nDevice,ma_IMMDevice**ppDevice) { Mr pThis->lpVtbl->Item(pThis,nDevice,ppDevice); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IMMDevice*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IMMDevice*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IMMDevice*pThis);
HRESULT (STDMETHODCALLTYPE*Activate) (ma_IMMDevice*pThis,const IID*const iid,DWORD dwClsCtx,MA_PROPVARIANT*pActivationParams,Mv**ppInterface);
HRESULT (STDMETHODCALLTYPE*OpenPropertyStore)(ma_IMMDevice*pThis,DWORD stgmAccess,ma_IPropertyStore**ppProperties);
HRESULT (STDMETHODCALLTYPE*GetId) (ma_IMMDevice*pThis,WCHAR**pID);
HRESULT (STDMETHODCALLTYPE*GetState) (ma_IMMDevice*pThis,DWORD*pState);
} ma_IMMDeviceVtbl;
struct ma_IMMDevice
{
ma_IMMDeviceVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IMMDevice_QueryInterface(ma_IMMDevice*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IMMDevice_AddRef(ma_IMMDevice*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IMMDevice_Release(ma_IMMDevice*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IMMDevice_Activate(ma_IMMDevice*pThis,const IID*const iid,DWORD dwClsCtx,MA_PROPVARIANT*pActivationParams,Mv**ppInterface) { Mr pThis->lpVtbl->Activate(pThis,iid,dwClsCtx,pActivationParams,ppInterface); }
static MA_INLINE HRESULT ma_IMMDevice_OpenPropertyStore(ma_IMMDevice*pThis,DWORD stgmAccess,ma_IPropertyStore**ppProperties) { Mr pThis->lpVtbl->OpenPropertyStore(pThis,stgmAccess,ppProperties); }
static MA_INLINE HRESULT ma_IMMDevice_GetId(ma_IMMDevice*pThis,WCHAR**pID) { Mr pThis->lpVtbl->GetId(pThis,pID); }
static MA_INLINE HRESULT ma_IMMDevice_GetState(ma_IMMDevice*pThis,DWORD*pState) { Mr pThis->lpVtbl->GetState(pThis,pState); }
#else
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IActivateAudioInterfaceAsyncOperation*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IActivateAudioInterfaceAsyncOperation*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IActivateAudioInterfaceAsyncOperation*pThis);
HRESULT (STDMETHODCALLTYPE*GetActivateResult)(ma_IActivateAudioInterfaceAsyncOperation*pThis,HRESULT*pActivateResult,ma_IUnknown**ppActivatedInterface);
} ma_IActivateAudioInterfaceAsyncOperationVtbl;
struct ma_IActivateAudioInterfaceAsyncOperation
{
ma_IActivateAudioInterfaceAsyncOperationVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_QueryInterface(ma_IActivateAudioInterfaceAsyncOperation*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IActivateAudioInterfaceAsyncOperation_AddRef(ma_IActivateAudioInterfaceAsyncOperation*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IActivateAudioInterfaceAsyncOperation_Release(ma_IActivateAudioInterfaceAsyncOperation*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(ma_IActivateAudioInterfaceAsyncOperation*pThis,HRESULT*pActivateResult,ma_IUnknown**ppActivatedInterface) { Mr pThis->lpVtbl->GetActivateResult(pThis,pActivateResult,ppActivatedInterface); }
#endif
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IPropertyStore*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IPropertyStore*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IPropertyStore*pThis);
HRESULT (STDMETHODCALLTYPE*GetCount)(ma_IPropertyStore*pThis,DWORD*pPropCount);
HRESULT (STDMETHODCALLTYPE*GetAt) (ma_IPropertyStore*pThis,DWORD propIndex,PROPERTYKEY*pPropKey);
HRESULT (STDMETHODCALLTYPE*GetValue)(ma_IPropertyStore*pThis,const PROPERTYKEY*const pKey,MA_PROPVARIANT*pPropVar);
HRESULT (STDMETHODCALLTYPE*SetValue)(ma_IPropertyStore*pThis,const PROPERTYKEY*const pKey,const MA_PROPVARIANT*const pPropVar);
HRESULT (STDMETHODCALLTYPE*Commit) (ma_IPropertyStore*pThis);
} ma_IPropertyStoreVtbl;
struct ma_IPropertyStore
{
ma_IPropertyStoreVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IPropertyStore_QueryInterface(ma_IPropertyStore*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IPropertyStore_AddRef(ma_IPropertyStore*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IPropertyStore_Release(ma_IPropertyStore*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IPropertyStore_GetCount(ma_IPropertyStore*pThis,DWORD*pPropCount) { Mr pThis->lpVtbl->GetCount(pThis,pPropCount); }
static MA_INLINE HRESULT ma_IPropertyStore_GetAt(ma_IPropertyStore*pThis,DWORD propIndex,PROPERTYKEY*pPropKey) { Mr pThis->lpVtbl->GetAt(pThis,propIndex,pPropKey); }
static MA_INLINE HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore*pThis,const PROPERTYKEY*const pKey,MA_PROPVARIANT*pPropVar) { Mr pThis->lpVtbl->GetValue(pThis,pKey,pPropVar); }
static MA_INLINE HRESULT ma_IPropertyStore_SetValue(ma_IPropertyStore*pThis,const PROPERTYKEY*const pKey,const MA_PROPVARIANT*const pPropVar) { Mr pThis->lpVtbl->SetValue(pThis,pKey,pPropVar); }
static MA_INLINE HRESULT ma_IPropertyStore_Commit(ma_IPropertyStore*pThis) { Mr pThis->lpVtbl->Commit(pThis); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IAudioClient*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IAudioClient*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IAudioClient*pThis);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IAudioClient*pThis,MA_AUDCLNT_SHAREMODE shareMode,DWORD streamFlags,MA_REFERENCE_TIME bufferDuration,MA_REFERENCE_TIME periodicity,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid);
HRESULT (STDMETHODCALLTYPE*GetBufferSize) (ma_IAudioClient*pThis,M3*pNumBufferFrames);
HRESULT (STDMETHODCALLTYPE*GetStreamLatency) (ma_IAudioClient*pThis,MA_REFERENCE_TIME*pLatency);
HRESULT (STDMETHODCALLTYPE*GetCurrentPadding)(ma_IAudioClient*pThis,M3*pNumPaddingFrames);
HRESULT (STDMETHODCALLTYPE*IsFormatSupported)(ma_IAudioClient*pThis,MA_AUDCLNT_SHAREMODE shareMode,const MA_WAVEFORMATEX*pFormat,MA_WAVEFORMATEX**ppClosestMatch);
HRESULT (STDMETHODCALLTYPE*GetMixFormat) (ma_IAudioClient*pThis,MA_WAVEFORMATEX**ppDeviceFormat);
HRESULT (STDMETHODCALLTYPE*GetDevicePeriod) (ma_IAudioClient*pThis,MA_REFERENCE_TIME*pDefaultDevicePeriod,MA_REFERENCE_TIME*pMinimumDevicePeriod);
HRESULT (STDMETHODCALLTYPE*Start) (ma_IAudioClient*pThis);
HRESULT (STDMETHODCALLTYPE*Stop) (ma_IAudioClient*pThis);
HRESULT (STDMETHODCALLTYPE*Reset) (ma_IAudioClient*pThis);
HRESULT (STDMETHODCALLTYPE*SetEventHandle) (ma_IAudioClient*pThis,HANDLE eventHandle);
HRESULT (STDMETHODCALLTYPE*GetService) (ma_IAudioClient*pThis,const IID*const riid,Mv**pp);
} ma_IAudioClientVtbl;
struct ma_IAudioClient
{
ma_IAudioClientVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioClient_QueryInterface(ma_IAudioClient*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IAudioClient_AddRef(ma_IAudioClient*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioClient_Release(ma_IAudioClient*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioClient_Initialize(ma_IAudioClient*pThis,MA_AUDCLNT_SHAREMODE shareMode,DWORD streamFlags,MA_REFERENCE_TIME bufferDuration,MA_REFERENCE_TIME periodicity,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid) { Mr pThis->lpVtbl->Initialize(pThis,shareMode,streamFlags,bufferDuration,periodicity,pFormat,pAudioSessionGuid); }
static MA_INLINE HRESULT ma_IAudioClient_GetBufferSize(ma_IAudioClient*pThis,M3*pNumBufferFrames) { Mr pThis->lpVtbl->GetBufferSize(pThis,pNumBufferFrames); }
static MA_INLINE HRESULT ma_IAudioClient_GetStreamLatency(ma_IAudioClient*pThis,MA_REFERENCE_TIME*pLatency) { Mr pThis->lpVtbl->GetStreamLatency(pThis,pLatency); }
static MA_INLINE HRESULT ma_IAudioClient_GetCurrentPadding(ma_IAudioClient*pThis,M3*pNumPaddingFrames) { Mr pThis->lpVtbl->GetCurrentPadding(pThis,pNumPaddingFrames); }
static MA_INLINE HRESULT ma_IAudioClient_IsFormatSupported(ma_IAudioClient*pThis,MA_AUDCLNT_SHAREMODE shareMode,const MA_WAVEFORMATEX*pFormat,MA_WAVEFORMATEX**ppClosestMatch) { Mr pThis->lpVtbl->IsFormatSupported(pThis,shareMode,pFormat,ppClosestMatch); }
static MA_INLINE HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient*pThis,MA_WAVEFORMATEX**ppDeviceFormat) { Mr pThis->lpVtbl->GetMixFormat(pThis,ppDeviceFormat); }
static MA_INLINE HRESULT ma_IAudioClient_GetDevicePeriod(ma_IAudioClient*pThis,MA_REFERENCE_TIME*pDefaultDevicePeriod,MA_REFERENCE_TIME*pMinimumDevicePeriod) { Mr pThis->lpVtbl->GetDevicePeriod(pThis,pDefaultDevicePeriod,pMinimumDevicePeriod); }
static MA_INLINE HRESULT ma_IAudioClient_Start(ma_IAudioClient*pThis) { Mr pThis->lpVtbl->Start(pThis); }
static MA_INLINE HRESULT ma_IAudioClient_Stop(ma_IAudioClient*pThis) { Mr pThis->lpVtbl->Stop(pThis); }
static MA_INLINE HRESULT ma_IAudioClient_Reset(ma_IAudioClient*pThis) { Mr pThis->lpVtbl->Reset(pThis); }
static MA_INLINE HRESULT ma_IAudioClient_SetEventHandle(ma_IAudioClient*pThis,HANDLE eventHandle) { Mr pThis->lpVtbl->SetEventHandle(pThis,eventHandle); }
static MA_INLINE HRESULT ma_IAudioClient_GetService(ma_IAudioClient*pThis,const IID*const riid,Mv**pp) { Mr pThis->lpVtbl->GetService(pThis,riid,pp); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IAudioClient2*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IAudioClient2*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IAudioClient2*pThis);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IAudioClient2*pThis,MA_AUDCLNT_SHAREMODE shareMode,DWORD streamFlags,MA_REFERENCE_TIME bufferDuration,MA_REFERENCE_TIME periodicity,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid);
HRESULT (STDMETHODCALLTYPE*GetBufferSize) (ma_IAudioClient2*pThis,M3*pNumBufferFrames);
HRESULT (STDMETHODCALLTYPE*GetStreamLatency) (ma_IAudioClient2*pThis,MA_REFERENCE_TIME*pLatency);
HRESULT (STDMETHODCALLTYPE*GetCurrentPadding)(ma_IAudioClient2*pThis,M3*pNumPaddingFrames);
HRESULT (STDMETHODCALLTYPE*IsFormatSupported)(ma_IAudioClient2*pThis,MA_AUDCLNT_SHAREMODE shareMode,const MA_WAVEFORMATEX*pFormat,MA_WAVEFORMATEX**ppClosestMatch);
HRESULT (STDMETHODCALLTYPE*GetMixFormat) (ma_IAudioClient2*pThis,MA_WAVEFORMATEX**ppDeviceFormat);
HRESULT (STDMETHODCALLTYPE*GetDevicePeriod) (ma_IAudioClient2*pThis,MA_REFERENCE_TIME*pDefaultDevicePeriod,MA_REFERENCE_TIME*pMinimumDevicePeriod);
HRESULT (STDMETHODCALLTYPE*Start) (ma_IAudioClient2*pThis);
HRESULT (STDMETHODCALLTYPE*Stop) (ma_IAudioClient2*pThis);
HRESULT (STDMETHODCALLTYPE*Reset) (ma_IAudioClient2*pThis);
HRESULT (STDMETHODCALLTYPE*SetEventHandle) (ma_IAudioClient2*pThis,HANDLE eventHandle);
HRESULT (STDMETHODCALLTYPE*GetService) (ma_IAudioClient2*pThis,const IID*const riid,Mv**pp);
HRESULT (STDMETHODCALLTYPE*IsOffloadCapable) (ma_IAudioClient2*pThis,MA_AUDIO_STREAM_CATEGORY category,BOOL*pOffloadCapable);
HRESULT (STDMETHODCALLTYPE*SetClientProperties)(ma_IAudioClient2*pThis,const ma_AudioClientProperties*pProperties);
HRESULT (STDMETHODCALLTYPE*GetBufferSizeLimits)(ma_IAudioClient2*pThis,const MA_WAVEFORMATEX*pFormat,BOOL eventDriven,MA_REFERENCE_TIME*pMinBufferDuration,MA_REFERENCE_TIME*pMaxBufferDuration);
} ma_IAudioClient2Vtbl;
struct ma_IAudioClient2
{
ma_IAudioClient2Vtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioClient2_QueryInterface(ma_IAudioClient2*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IAudioClient2_AddRef(ma_IAudioClient2*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioClient2_Release(ma_IAudioClient2*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioClient2_Initialize(ma_IAudioClient2*pThis,MA_AUDCLNT_SHAREMODE shareMode,DWORD streamFlags,MA_REFERENCE_TIME bufferDuration,MA_REFERENCE_TIME periodicity,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid) { Mr pThis->lpVtbl->Initialize(pThis,shareMode,streamFlags,bufferDuration,periodicity,pFormat,pAudioSessionGuid); }
static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSize(ma_IAudioClient2*pThis,M3*pNumBufferFrames) { Mr pThis->lpVtbl->GetBufferSize(pThis,pNumBufferFrames); }
static MA_INLINE HRESULT ma_IAudioClient2_GetStreamLatency(ma_IAudioClient2*pThis,MA_REFERENCE_TIME*pLatency) { Mr pThis->lpVtbl->GetStreamLatency(pThis,pLatency); }
static MA_INLINE HRESULT ma_IAudioClient2_GetCurrentPadding(ma_IAudioClient2*pThis,M3*pNumPaddingFrames) { Mr pThis->lpVtbl->GetCurrentPadding(pThis,pNumPaddingFrames); }
static MA_INLINE HRESULT ma_IAudioClient2_IsFormatSupported(ma_IAudioClient2*pThis,MA_AUDCLNT_SHAREMODE shareMode,const MA_WAVEFORMATEX*pFormat,MA_WAVEFORMATEX**ppClosestMatch) { Mr pThis->lpVtbl->IsFormatSupported(pThis,shareMode,pFormat,ppClosestMatch); }
static MA_INLINE HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2*pThis,MA_WAVEFORMATEX**ppDeviceFormat) { Mr pThis->lpVtbl->GetMixFormat(pThis,ppDeviceFormat); }
static MA_INLINE HRESULT ma_IAudioClient2_GetDevicePeriod(ma_IAudioClient2*pThis,MA_REFERENCE_TIME*pDefaultDevicePeriod,MA_REFERENCE_TIME*pMinimumDevicePeriod) { Mr pThis->lpVtbl->GetDevicePeriod(pThis,pDefaultDevicePeriod,pMinimumDevicePeriod); }
static MA_INLINE HRESULT ma_IAudioClient2_Start(ma_IAudioClient2*pThis) { Mr pThis->lpVtbl->Start(pThis); }
static MA_INLINE HRESULT ma_IAudioClient2_Stop(ma_IAudioClient2*pThis) { Mr pThis->lpVtbl->Stop(pThis); }
static MA_INLINE HRESULT ma_IAudioClient2_Reset(ma_IAudioClient2*pThis) { Mr pThis->lpVtbl->Reset(pThis); }
static MA_INLINE HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2*pThis,HANDLE eventHandle) { Mr pThis->lpVtbl->SetEventHandle(pThis,eventHandle); }
static MA_INLINE HRESULT ma_IAudioClient2_GetService(ma_IAudioClient2*pThis,const IID*const riid,Mv**pp) { Mr pThis->lpVtbl->GetService(pThis,riid,pp); }
static MA_INLINE HRESULT ma_IAudioClient2_IsOffloadCapable(ma_IAudioClient2*pThis,MA_AUDIO_STREAM_CATEGORY category,BOOL*pOffloadCapable) { Mr pThis->lpVtbl->IsOffloadCapable(pThis,category,pOffloadCapable); }
static MA_INLINE HRESULT ma_IAudioClient2_SetClientProperties(ma_IAudioClient2*pThis,const ma_AudioClientProperties*pProperties) { Mr pThis->lpVtbl->SetClientProperties(pThis,pProperties); }
static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSizeLimits(ma_IAudioClient2*pThis,const MA_WAVEFORMATEX*pFormat,BOOL eventDriven,MA_REFERENCE_TIME*pMinBufferDuration,MA_REFERENCE_TIME*pMaxBufferDuration) { Mr pThis->lpVtbl->GetBufferSizeLimits(pThis,pFormat,eventDriven,pMinBufferDuration,pMaxBufferDuration); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IAudioClient3*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IAudioClient3*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IAudioClient3*pThis);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IAudioClient3*pThis,MA_AUDCLNT_SHAREMODE shareMode,DWORD streamFlags,MA_REFERENCE_TIME bufferDuration,MA_REFERENCE_TIME periodicity,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid);
HRESULT (STDMETHODCALLTYPE*GetBufferSize) (ma_IAudioClient3*pThis,M3*pNumBufferFrames);
HRESULT (STDMETHODCALLTYPE*GetStreamLatency) (ma_IAudioClient3*pThis,MA_REFERENCE_TIME*pLatency);
HRESULT (STDMETHODCALLTYPE*GetCurrentPadding)(ma_IAudioClient3*pThis,M3*pNumPaddingFrames);
HRESULT (STDMETHODCALLTYPE*IsFormatSupported)(ma_IAudioClient3*pThis,MA_AUDCLNT_SHAREMODE shareMode,const MA_WAVEFORMATEX*pFormat,MA_WAVEFORMATEX**ppClosestMatch);
HRESULT (STDMETHODCALLTYPE*GetMixFormat) (ma_IAudioClient3*pThis,MA_WAVEFORMATEX**ppDeviceFormat);
HRESULT (STDMETHODCALLTYPE*GetDevicePeriod) (ma_IAudioClient3*pThis,MA_REFERENCE_TIME*pDefaultDevicePeriod,MA_REFERENCE_TIME*pMinimumDevicePeriod);
HRESULT (STDMETHODCALLTYPE*Start) (ma_IAudioClient3*pThis);
HRESULT (STDMETHODCALLTYPE*Stop) (ma_IAudioClient3*pThis);
HRESULT (STDMETHODCALLTYPE*Reset) (ma_IAudioClient3*pThis);
HRESULT (STDMETHODCALLTYPE*SetEventHandle) (ma_IAudioClient3*pThis,HANDLE eventHandle);
HRESULT (STDMETHODCALLTYPE*GetService) (ma_IAudioClient3*pThis,const IID*const riid,Mv**pp);
HRESULT (STDMETHODCALLTYPE*IsOffloadCapable) (ma_IAudioClient3*pThis,MA_AUDIO_STREAM_CATEGORY category,BOOL*pOffloadCapable);
HRESULT (STDMETHODCALLTYPE*SetClientProperties)(ma_IAudioClient3*pThis,const ma_AudioClientProperties*pProperties);
HRESULT (STDMETHODCALLTYPE*GetBufferSizeLimits)(ma_IAudioClient3*pThis,const MA_WAVEFORMATEX*pFormat,BOOL eventDriven,MA_REFERENCE_TIME*pMinBufferDuration,MA_REFERENCE_TIME*pMaxBufferDuration);
HRESULT (STDMETHODCALLTYPE*GetSharedModeEnginePeriod) (ma_IAudioClient3*pThis,const MA_WAVEFORMATEX*pFormat,M3*pDefaultPeriodInFrames,M3*pFundamentalPeriodInFrames,M3*pMinPeriodInFrames,M3*pMaxPeriodInFrames);
HRESULT (STDMETHODCALLTYPE*GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3*pThis,MA_WAVEFORMATEX**ppFormat,M3*pCurrentPeriodInFrames);
HRESULT (STDMETHODCALLTYPE*InitializeSharedAudioStream) (ma_IAudioClient3*pThis,DWORD streamFlags,M3 periodInFrames,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid);
} ma_IAudioClient3Vtbl;
struct ma_IAudioClient3
{
ma_IAudioClient3Vtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioClient3_QueryInterface(ma_IAudioClient3*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IAudioClient3_AddRef(ma_IAudioClient3*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioClient3_Release(ma_IAudioClient3*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioClient3_Initialize(ma_IAudioClient3*pThis,MA_AUDCLNT_SHAREMODE shareMode,DWORD streamFlags,MA_REFERENCE_TIME bufferDuration,MA_REFERENCE_TIME periodicity,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGuid) { Mr pThis->lpVtbl->Initialize(pThis,shareMode,streamFlags,bufferDuration,periodicity,pFormat,pAudioSessionGuid); }
static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSize(ma_IAudioClient3*pThis,M3*pNumBufferFrames) { Mr pThis->lpVtbl->GetBufferSize(pThis,pNumBufferFrames); }
static MA_INLINE HRESULT ma_IAudioClient3_GetStreamLatency(ma_IAudioClient3*pThis,MA_REFERENCE_TIME*pLatency) { Mr pThis->lpVtbl->GetStreamLatency(pThis,pLatency); }
static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentPadding(ma_IAudioClient3*pThis,M3*pNumPaddingFrames) { Mr pThis->lpVtbl->GetCurrentPadding(pThis,pNumPaddingFrames); }
static MA_INLINE HRESULT ma_IAudioClient3_IsFormatSupported(ma_IAudioClient3*pThis,MA_AUDCLNT_SHAREMODE shareMode,const MA_WAVEFORMATEX*pFormat,MA_WAVEFORMATEX**ppClosestMatch) { Mr pThis->lpVtbl->IsFormatSupported(pThis,shareMode,pFormat,ppClosestMatch); }
static MA_INLINE HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3*pThis,MA_WAVEFORMATEX**ppDeviceFormat) { Mr pThis->lpVtbl->GetMixFormat(pThis,ppDeviceFormat); }
static MA_INLINE HRESULT ma_IAudioClient3_GetDevicePeriod(ma_IAudioClient3*pThis,MA_REFERENCE_TIME*pDefaultDevicePeriod,MA_REFERENCE_TIME*pMinimumDevicePeriod) { Mr pThis->lpVtbl->GetDevicePeriod(pThis,pDefaultDevicePeriod,pMinimumDevicePeriod); }
static MA_INLINE HRESULT ma_IAudioClient3_Start(ma_IAudioClient3*pThis) { Mr pThis->lpVtbl->Start(pThis); }
static MA_INLINE HRESULT ma_IAudioClient3_Stop(ma_IAudioClient3*pThis) { Mr pThis->lpVtbl->Stop(pThis); }
static MA_INLINE HRESULT ma_IAudioClient3_Reset(ma_IAudioClient3*pThis) { Mr pThis->lpVtbl->Reset(pThis); }
static MA_INLINE HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3*pThis,HANDLE eventHandle) { Mr pThis->lpVtbl->SetEventHandle(pThis,eventHandle); }
static MA_INLINE HRESULT ma_IAudioClient3_GetService(ma_IAudioClient3*pThis,const IID*const riid,Mv**pp) { Mr pThis->lpVtbl->GetService(pThis,riid,pp); }
static MA_INLINE HRESULT ma_IAudioClient3_IsOffloadCapable(ma_IAudioClient3*pThis,MA_AUDIO_STREAM_CATEGORY category,BOOL*pOffloadCapable) { Mr pThis->lpVtbl->IsOffloadCapable(pThis,category,pOffloadCapable); }
static MA_INLINE HRESULT ma_IAudioClient3_SetClientProperties(ma_IAudioClient3*pThis,const ma_AudioClientProperties*pProperties) { Mr pThis->lpVtbl->SetClientProperties(pThis,pProperties); }
static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSizeLimits(ma_IAudioClient3*pThis,const MA_WAVEFORMATEX*pFormat,BOOL eventDriven,MA_REFERENCE_TIME*pMinBufferDuration,MA_REFERENCE_TIME*pMaxBufferDuration) { Mr pThis->lpVtbl->GetBufferSizeLimits(pThis,pFormat,eventDriven,pMinBufferDuration,pMaxBufferDuration); }
static MA_INLINE HRESULT ma_IAudioClient3_GetSharedModeEnginePeriod(ma_IAudioClient3*pThis,const MA_WAVEFORMATEX*pFormat,M3*pDefaultPeriodInFrames,M3*pFundamentalPeriodInFrames,M3*pMinPeriodInFrames,M3*pMaxPeriodInFrames) { Mr pThis->lpVtbl->GetSharedModeEnginePeriod(pThis,pFormat,pDefaultPeriodInFrames,pFundamentalPeriodInFrames,pMinPeriodInFrames,pMaxPeriodInFrames); }
static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3*pThis,MA_WAVEFORMATEX**ppFormat,M3*pCurrentPeriodInFrames) { Mr pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis,ppFormat,pCurrentPeriodInFrames); }
static MA_INLINE HRESULT ma_IAudioClient3_InitializeSharedAudioStream(ma_IAudioClient3*pThis,DWORD streamFlags,M3 periodInFrames,const MA_WAVEFORMATEX*pFormat,const GUID*pAudioSessionGUID) { Mr pThis->lpVtbl->InitializeSharedAudioStream(pThis,streamFlags,periodInFrames,pFormat,pAudioSessionGUID); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IAudioRenderClient*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IAudioRenderClient*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IAudioRenderClient*pThis);
HRESULT (STDMETHODCALLTYPE*GetBuffer) (ma_IAudioRenderClient*pThis,M3 numFramesRequested,BYTE**ppData);
HRESULT (STDMETHODCALLTYPE*ReleaseBuffer)(ma_IAudioRenderClient*pThis,M3 numFramesWritten,DWORD dwFlags);
} ma_IAudioRenderClientVtbl;
struct ma_IAudioRenderClient
{
ma_IAudioRenderClientVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioRenderClient_Release(ma_IAudioRenderClient*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient*pThis,M3 numFramesRequested,BYTE**ppData) { Mr pThis->lpVtbl->GetBuffer(pThis,numFramesRequested,ppData); }
static MA_INLINE HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient*pThis,M3 numFramesWritten,DWORD dwFlags) { Mr pThis->lpVtbl->ReleaseBuffer(pThis,numFramesWritten,dwFlags); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IAudioCaptureClient*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IAudioCaptureClient*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IAudioCaptureClient*pThis);
HRESULT (STDMETHODCALLTYPE*GetBuffer) (ma_IAudioCaptureClient*pThis,BYTE**ppData,M3*pNumFramesToRead,DWORD*pFlags,M6*pDevicePosition,M6*pQPCPosition);
HRESULT (STDMETHODCALLTYPE*ReleaseBuffer) (ma_IAudioCaptureClient*pThis,M3 numFramesRead);
HRESULT (STDMETHODCALLTYPE*GetNextPacketSize)(ma_IAudioCaptureClient*pThis,M3*pNumFramesInNextPacket);
} ma_IAudioCaptureClientVtbl;
struct ma_IAudioCaptureClient
{
ma_IAudioCaptureClientVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient*pThis,BYTE**ppData,M3*pNumFramesToRead,DWORD*pFlags,M6*pDevicePosition,M6*pQPCPosition) { Mr pThis->lpVtbl->GetBuffer(pThis,ppData,pNumFramesToRead,pFlags,pDevicePosition,pQPCPosition); }
static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient*pThis,M3 numFramesRead) { Mr pThis->lpVtbl->ReleaseBuffer(pThis,numFramesRead); }
static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient*pThis,M3*pNumFramesInNextPacket) { Mr pThis->lpVtbl->GetNextPacketSize(pThis,pNumFramesInNextPacket); }
#if defined(MA_WIN32_UWP)
typedef HRESULT (WINAPI*MA_PFN_ActivateAudioInterfaceAsync)(const wchar_t*deviceInterfacePath,const IID*riid,MA_PROPVARIANT*activationParams,ma_IActivateAudioInterfaceCompletionHandler*completionHandler,ma_IActivateAudioInterfaceAsyncOperation**activationOperation);
#endif
typedef HANDLE (WINAPI*MA_PFN_AvSetMmThreadCharacteristicsA)(const char*TaskName,DWORD*TaskIndex);
typedef BOOL (WINAPI*MA_PFN_AvRevertMmThreadCharacteristics)(HANDLE AvrtHandle);
#if !defined(MA_WIN32_DESKTOP)&&!defined(MA_WIN32_GDK)
typedef struct ma_completion_handler_uwp ma_completion_handler_uwp;
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_completion_handler_uwp*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_completion_handler_uwp*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_completion_handler_uwp*pThis);
HRESULT (STDMETHODCALLTYPE*ActivateCompleted)(ma_completion_handler_uwp*pThis,ma_IActivateAudioInterfaceAsyncOperation*pActivateOperation);
} ma_completion_handler_uwp_vtbl;
struct ma_completion_handler_uwp
{
ma_completion_handler_uwp_vtbl*lpVtbl;
MA_ATOMIC(4,M3) counter;
HANDLE hEvent;
};
static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp*pThis,const IID*const riid,Mv**ppObject)
{
if (!ma_is_guid_equal(riid,&MA_IID_IUnknown)&&!ma_is_guid_equal(riid,&MA_IID_IActivateAudioInterfaceCompletionHandler)&&!ma_is_guid_equal(riid,&MA_IID_IAgileObject)) {
*ppObject=NULL;
Mr E_NOINTERFACE;
}
*ppObject=(Mv*)pThis;
((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
Mr S_OK;
}
static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp*pThis)
{
Mr (ULONG)ma_atomic_fetch_add_32(&pThis->counter,1)+1;
}
static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp*pThis)
{
M3 newRefCount=ma_atomic_fetch_sub_32(&pThis->counter,1)-1;
if (newRefCount==0) {
Mr 0;
}
Mr (ULONG)newRefCount;
}
static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp*pThis,ma_IActivateAudioInterfaceAsyncOperation*pActivateOperation)
{
(Mv)pActivateOperation;
SetEvent(pThis->hEvent);
Mr S_OK;
}
static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance={
ma_completion_handler_uwp_QueryInterface,ma_completion_handler_uwp_AddRef,ma_completion_handler_uwp_Release,ma_completion_handler_uwp_ActivateCompleted
};
static Me ma_completion_handler_uwp_init(ma_completion_handler_uwp*pHandler)
{
MA_ASSERT(pHandler !=NULL);
MA_ZERO_OBJECT(pHandler);
pHandler->lpVtbl=&g_maCompletionHandlerVtblInstance;
pHandler->counter=1;
pHandler->hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
if (pHandler->hEvent==NULL) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Mv ma_completion_handler_uwp_uninit(ma_completion_handler_uwp*pHandler)
{
if (pHandler->hEvent !=NULL) {
CloseHandle(pHandler->hEvent);
}
}
static Mv ma_completion_handler_uwp_wait(ma_completion_handler_uwp*pHandler)
{
WaitForSingleObject((HANDLE)pHandler->hEvent,INFINITE);
}
#endif
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient*pThis,const IID*const riid,Mv**ppObject)
{
if (!ma_is_guid_equal(riid,&MA_IID_IUnknown)&&!ma_is_guid_equal(riid,&MA_IID_IMMNotificationClient)) {
*ppObject=NULL;
Mr E_NOINTERFACE;
}
*ppObject=(Mv*)pThis;
((ma_IMMNotificationClientVtbl*)pThis->lpVtbl)->AddRef(pThis);
Mr S_OK;
}
static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient*pThis)
{
Mr (ULONG)ma_atomic_fetch_add_32(&pThis->counter,1)+1;
}
static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificationClient*pThis)
{
M3 newRefCount=ma_atomic_fetch_sub_32(&pThis->counter,1)-1;
if (newRefCount==0) {
Mr 0;
}
Mr (ULONG)newRefCount;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID,DWORD dwNewState)
{
ma_bool32 isThisDevice=MA_FALSE;
ma_bool32 isCapture=MA_FALSE;
ma_bool32 isPlayback=MA_FALSE;
#ifdef MA_DEBUG_OUTPUT
#endif
if (pThis->Md->wasapi.allowCaptureAutoStreamRouting&&(pThis->Md->type==ma_device_type_capture||pThis->Md->type==ma_device_type_duplex||pThis->Md->type==ma_device_type_loopback)) {
isCapture=MA_TRUE;
if (ma_strcmp_WCHAR(pThis->Md->capture.id.wasapi,pDeviceID)==0) {
isThisDevice=MA_TRUE;
}
}
if (pThis->Md->wasapi.allowPlaybackAutoStreamRouting&&(pThis->Md->type==Mt||pThis->Md->type==ma_device_type_duplex)) {
isPlayback=MA_TRUE;
if (ma_strcmp_WCHAR(pThis->Md->playback.id.wasapi,pDeviceID)==0) {
isThisDevice=MA_TRUE;
}
}
if (isThisDevice) {
if ((dwNewState&MA_MM_DEVICE_STATE_ACTIVE)==0) {
if (ma_device_get_state(pThis->Md)==ma_device_state_started) {
if (isPlayback) {
 pThis->Md->wasapi.isDetachedPlayback=MA_TRUE;
}
if (isCapture) {
 pThis->Md->wasapi.isDetachedCapture=MA_TRUE;
}
ma_device_stop(pThis->Md);
}
}
if ((dwNewState&MA_MM_DEVICE_STATE_ACTIVE) !=0) {
ma_bool8 tryRestartingDevice=MA_FALSE;
if (isPlayback) {
if (pThis->Md->wasapi.isDetachedPlayback) {
 pThis->Md->wasapi.isDetachedPlayback=MA_FALSE;
 ma_device_reroute__wasapi(pThis->Md,Mt);
 tryRestartingDevice=MA_TRUE;
}
}
if (isCapture) {
if (pThis->Md->wasapi.isDetachedCapture) {
 pThis->Md->wasapi.isDetachedCapture=MA_FALSE;
 ma_device_reroute__wasapi(pThis->Md,(pThis->Md->type==ma_device_type_loopback)?ma_device_type_loopback:ma_device_type_capture);
 tryRestartingDevice=MA_TRUE;
}
}
if (tryRestartingDevice) {
if (pThis->Md->wasapi.isDetachedPlayback==MA_FALSE&&pThis->Md->wasapi.isDetachedCapture==MA_FALSE) {
 ma_device_start(pThis->Md);
}
}
}
}
Mr S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID)
{
#ifdef MA_DEBUG_OUTPUT
#endif
(Mv)pThis;
(Mv)pDeviceID;
Mr S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID)
{
#ifdef MA_DEBUG_OUTPUT
#endif
(Mv)pThis;
(Mv)pDeviceID;
Mr S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient*pThis,ma_EDataFlow dataFlow,ma_ERole role,const WCHAR*pDefaultDeviceID)
{
#ifdef MA_DEBUG_OUTPUT
#endif
(Mv)role;
if ((pThis->Md->type==Mt&&dataFlow !=ma_eRender)||
(pThis->Md->type==ma_device_type_capture&&dataFlow !=ma_eCapture)||
(pThis->Md->type==ma_device_type_loopback&&dataFlow !=ma_eRender)) {
ma_log_postf(ma_device_get_log(pThis->Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because dataFlow does match device type.\n");
Mr S_OK;
}
if (pThis->Md->type==ma_device_type_loopback) {
dataFlow=ma_eCapture;
}
if ((dataFlow==ma_eRender&&pThis->Md->wasapi.allowPlaybackAutoStreamRouting==MA_FALSE)||
(dataFlow==ma_eCapture&&pThis->Md->wasapi.allowCaptureAutoStreamRouting==MA_FALSE)) {
ma_log_postf(ma_device_get_log(pThis->Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because automatic stream routing has been disabled by the device config.\n");
Mr S_OK;
}
if ((dataFlow==ma_eRender&&pThis->Md->playback.shareMode==ma_share_mode_exclusive)||
(dataFlow==ma_eCapture&&pThis->Md->capture.shareMode==ma_share_mode_exclusive)) {
ma_log_postf(ma_device_get_log(pThis->Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because the device shared mode is exclusive.\n");
Mr S_OK;
}
{
M3 previousState=ma_device_get_state(pThis->Md);
ma_bool8 restartDevice=MA_FALSE;
if (previousState==ma_device_state_uninitialized||previousState==ma_device_state_starting) {
ma_log_postf(ma_device_get_log(pThis->Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because the device is in the process of starting.\n");
Mr S_OK;
}
if (previousState==ma_device_state_started) {
ma_device_stop(pThis->Md);
restartDevice=MA_TRUE;
}
if (pDefaultDeviceID !=NULL) {
ma_mutex_lock(&pThis->Md->wasapi.rerouteLock);
{
if (dataFlow==ma_eRender) {
 ma_device_reroute__wasapi(pThis->Md,Mt);
 if (pThis->Md->wasapi.isDetachedPlayback) {
 pThis->Md->wasapi.isDetachedPlayback=MA_FALSE;
 if (pThis->Md->type==ma_device_type_duplex&&pThis->Md->wasapi.isDetachedCapture) {
 restartDevice=MA_FALSE;
 }
 else {
 restartDevice=MA_TRUE;
 }
 }
}
else {
 ma_device_reroute__wasapi(pThis->Md,(pThis->Md->type==ma_device_type_loopback)?ma_device_type_loopback:ma_device_type_capture);
 if (pThis->Md->wasapi.isDetachedCapture) {
 pThis->Md->wasapi.isDetachedCapture=MA_FALSE;
 if (pThis->Md->type==ma_device_type_duplex&&pThis->Md->wasapi.isDetachedPlayback) {
 restartDevice=MA_FALSE;
 }
 else {
 restartDevice=MA_TRUE;
 }
 }
}
}
ma_mutex_unlock(&pThis->Md->wasapi.rerouteLock);
if (restartDevice) {
ma_device_start(pThis->Md);
}
}
}
Mr S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient*pThis,const WCHAR*pDeviceID,const PROPERTYKEY key)
{
#ifdef MA_DEBUG_OUTPUT
#endif
(Mv)pThis;
(Mv)pDeviceID;
(Mv)key;
Mr S_OK;
}
static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl={
ma_IMMNotificationClient_QueryInterface,ma_IMMNotificationClient_AddRef,ma_IMMNotificationClient_Release,ma_IMMNotificationClient_OnDeviceStateChanged,ma_IMMNotificationClient_OnDeviceAdded,ma_IMMNotificationClient_OnDeviceRemoved,ma_IMMNotificationClient_OnDefaultDeviceChanged,ma_IMMNotificationClient_OnPropertyValueChanged
};
#endif
static const char*ma_to_usage_string__wasapi(ma_wasapi_usage usage)
{
switch (usage)
{
case ma_wasapi_usage_default:Mr NULL;
case ma_wasapi_usage_games: Mr "Games";
case ma_wasapi_usage_pro_audio: Mr "Pro Audio";
default:break;
}
Mr NULL;
}
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
typedef ma_IMMDevice ma_WASAPIDeviceInterface;
#else
typedef ma_IUnknown ma_WASAPIDeviceInterface;
#endif
#define MA_CONTEXT_COMMAND_QUIT__WASAPI 1
#define MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI 2
#define MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI 3
static ma_context_command__wasapi ma_context_init_command__wasapi(int code)
{
ma_context_command__wasapi cmd;
MA_ZERO_OBJECT(&cmd);
cmd.code=code;
Mr cmd;
}
static Me ma_context_post_command__wasapi(ma_context*Mc,const ma_context_command__wasapi*pCmd)
{
Me Mf;
ma_bool32 isUsingLocalEvent=MA_FALSE;
ma_event localEvent;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pCmd !=NULL);
if (pCmd->pEvent==NULL) {
isUsingLocalEvent=MA_TRUE;
Mf=ma_event_init(&localEvent);
if (Mf !=Ms) {
Mr Mf;
}
}
ma_mutex_lock(&Mc->wasapi.commandLock);
{
M3 index;
while (Mc->wasapi.commandCount==ma_countof(Mc->wasapi.commands)) {
ma_yield();
}
index=(Mc->wasapi.commandIndex+Mc->wasapi.commandCount) % ma_countof(Mc->wasapi.commands);
Mc->wasapi.commands[index]=*pCmd;
Mc->wasapi.commands[index].pEvent=&localEvent;
Mc->wasapi.commandCount+=1;
ma_semaphore_release(&Mc->wasapi.commandSem);
}
ma_mutex_unlock(&Mc->wasapi.commandLock);
if (isUsingLocalEvent) {
ma_event_wait(&localEvent);
ma_event_uninit(&localEvent);
}
Mr Ms;
}
static Me ma_context_next_command__wasapi(ma_context*Mc,ma_context_command__wasapi*pCmd)
{
Me Mf=Ms;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pCmd !=NULL);
Mf=ma_semaphore_wait(&Mc->wasapi.commandSem);
if (Mf==Ms) {
ma_mutex_lock(&Mc->wasapi.commandLock);
{
*pCmd=Mc->wasapi.commands[Mc->wasapi.commandIndex];
Mc->wasapi.commandIndex=(Mc->wasapi.commandIndex+1) % ma_countof(Mc->wasapi.commands);
Mc->wasapi.commandCount-=1;
}
ma_mutex_unlock(&Mc->wasapi.commandLock);
}
Mr Mf;
}
static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(Mv*pUserData)
{
Me Mf;
ma_context*Mc=(ma_context*)pUserData;
MA_ASSERT(Mc !=NULL);
for (;;) {
ma_context_command__wasapi cmd;
Mf=ma_context_next_command__wasapi(Mc,&cmd);
if (Mf !=Ms) {
break;
}
switch (cmd.code)
{
case MA_CONTEXT_COMMAND_QUIT__WASAPI:
{
} break;
case MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI:
{
if (cmd.data.createAudioClient.deviceType==Mt) {
*cmd.data.createAudioClient.pResult=ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient,&MA_IID_IAudioRenderClient,cmd.data.createAudioClient.ppAudioClientService));
} else {
*cmd.data.createAudioClient.pResult=ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient,&MA_IID_IAudioCaptureClient,cmd.data.createAudioClient.ppAudioClientService));
}
} break;
case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI:
{
if (cmd.data.releaseAudioClient.deviceType==Mt) {
 if (cmd.data.releaseAudioClient.Md->wasapi.pAudioClientPlayback !=NULL) {
 ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.Md->wasapi.pAudioClientPlayback);
 cmd.data.releaseAudioClient.Md->wasapi.pAudioClientPlayback=NULL;
 }
}
if (cmd.data.releaseAudioClient.deviceType==ma_device_type_capture) {
 if (cmd.data.releaseAudioClient.Md->wasapi.pAudioClientCapture !=NULL) {
 ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.Md->wasapi.pAudioClientCapture);
 cmd.data.releaseAudioClient.Md->wasapi.pAudioClientCapture=NULL;
 }
}
} break;
default:
{
MA_ASSERT(MA_FALSE);
} break;
}
if (cmd.pEvent !=NULL) {
ma_event_signal(cmd.pEvent);
}
if (cmd.code==MA_CONTEXT_COMMAND_QUIT__WASAPI) {
break;
}
}
Mr (ma_thread_result)0;
}
static Me ma_device_create_IAudioClient_service__wasapi(ma_context*Mc,ma_device_type deviceType,ma_IAudioClient*pAudioClient,Mv**ppAudioClientService)
{
Me Mf;
Me cmdResult;
ma_context_command__wasapi cmd=ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI);
cmd.data.createAudioClient.deviceType=deviceType;
cmd.data.createAudioClient.pAudioClient=(Mv*)pAudioClient;
cmd.data.createAudioClient.ppAudioClientService=ppAudioClientService;
cmd.data.createAudioClient.pResult=&cmdResult;
Mf=ma_context_post_command__wasapi(Mc,&cmd);
if (Mf !=Ms) {
Mr Mf;
}
Mr*cmd.data.createAudioClient.pResult;
}
#if 0
static Me ma_device_release_IAudioClient_service__wasapi(ma_device*Md,ma_device_type deviceType)
{
Me Mf;
ma_context_command__wasapi cmd=ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI);
cmd.data.releaseAudioClient.Md=Md;
cmd.data.releaseAudioClient.deviceType=deviceType;
Mf=ma_context_post_command__wasapi(Md->Mc,&cmd);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
#endif
static Mv ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const MA_WAVEFORMATEX*pWF,ma_share_mode shareMode,ma_device_info*pInfo)
{
MA_ASSERT(pWF !=NULL);
MA_ASSERT(pInfo !=NULL);
if (pInfo->nativeDataFormatCount>=ma_countof(pInfo->nativeDataFormats)) {
Mr;
}
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].format=ma_format_from_WAVEFORMATEX(pWF);
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].Mh=pWF->nChannels;
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].sampleRate=pWF->nSamplesPerSec;
pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].flags=(shareMode==ma_share_mode_exclusive)?MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE:0;
pInfo->nativeDataFormatCount+=1;
}
static Me ma_context_get_device_info_from_IAudioClient__wasapi(ma_context*Mc,Mv*pMMDevice,ma_IAudioClient*pAudioClient,ma_device_info*pInfo)
{
HRESULT hr;
MA_WAVEFORMATEX*pWF=NULL;
MA_ASSERT(pAudioClient !=NULL);
MA_ASSERT(pInfo !=NULL);
hr=ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient,(MA_WAVEFORMATEX**)&pWF);
if (SUCCEEDED(hr)) {
ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF,ma_share_mode_shared,pInfo);
} else {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.");
Mr ma_result_from_HRESULT(hr);
}
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
{
ma_IPropertyStore*pProperties;
hr=ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice,STGM_READ,&pProperties);
if (SUCCEEDED(hr)) {
MA_PROPVARIANT var;
ma_PropVariantInit(&var);
hr=ma_IPropertyStore_GetValue(pProperties,&MA_PKEY_AudioEngine_DeviceFormat,&var);
if (SUCCEEDED(hr)) {
pWF=(MA_WAVEFORMATEX*)var.blob.pBlobData;
hr=ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient,MA_AUDCLNT_SHAREMODE_EXCLUSIVE,pWF,NULL);
if (SUCCEEDED(hr)) {
 ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF,ma_share_mode_exclusive,pInfo);
} else {
 M3 Mh=pWF->nChannels;
 ma_channel defaultChannelMap[MA_MAX_CHANNELS];
 MA_WAVEFORMATEXTENSIBLE wf;
 ma_bool32 found;
 M3 iFormat;
 if (Mh>MA_MAX_CHANNELS) {
 Mh=MA_MAX_CHANNELS;
 }
 ma_channel_map_init_standard(ma_standard_channel_map_microsoft,defaultChannelMap,ma_countof(defaultChannelMap),Mh);
 MA_ZERO_OBJECT(&wf);
 wf.cbSize=sizeof(wf);
 wf.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
 wf.nChannels=(WORD)Mh;
 wf.dwChannelMask=ma_channel_map_to_channel_mask__win32(defaultChannelMap,Mh);
 found=MA_FALSE;
 for (iFormat=0; iFormat<ma_countof(g_maFormatPriorities);++iFormat) {
 ma_format format=g_maFormatPriorities[iFormat];
 M3 iSampleRate;
 wf.wBitsPerSample=(WORD)(ma_get_bytes_per_sample(format)*8);
 wf.nBlockAlign=(WORD)(wf.nChannels*wf.wBitsPerSample / 8);
 wf.nAvgBytesPerSec=wf.nBlockAlign*wf.nSamplesPerSec;
 wf.Samples.wValidBitsPerSample=wf.wBitsPerSample;
 if (format==ma_format_f32) {
 wf.SubFormat=MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
 } else {
 wf.SubFormat=MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
 }
 for (iSampleRate=0; iSampleRate<ma_countof(g_maStandardSampleRatePriorities);++iSampleRate) {
 wf.nSamplesPerSec=g_maStandardSampleRatePriorities[iSampleRate];
 hr=ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient,MA_AUDCLNT_SHAREMODE_EXCLUSIVE,(MA_WAVEFORMATEX*)&wf,NULL);
 if (SUCCEEDED(hr)) {
 ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((MA_WAVEFORMATEX*)&wf,ma_share_mode_exclusive,pInfo);
 found=MA_TRUE;
 break;
 }
 }
 if (found) {
 break;
 }
 }
 ma_PropVariantClear(Mc,&var);
 if (!found) {
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval.");
 }
}
} else {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval.");
}
ma_IPropertyStore_Release(pProperties);
} else {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval.");
}
}
#else
{
(Mv)pMMDevice;
}
#endif
Mr Ms;
}
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType)
{
if (deviceType==Mt) {
Mr ma_eRender;
} else if (deviceType==ma_device_type_capture) {
Mr ma_eCapture;
} else {
MA_ASSERT(MA_FALSE);
Mr ma_eRender;
}
}
static Me ma_context_create_IMMDeviceEnumerator__wasapi(ma_context*Mc,ma_IMMDeviceEnumerator**ppDeviceEnumerator)
{
HRESULT hr;
ma_IMMDeviceEnumerator*pDeviceEnumerator;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppDeviceEnumerator !=NULL);
*ppDeviceEnumerator=NULL;
hr=ma_CoCreateInstance(Mc,&MA_CLSID_MMDeviceEnumerator,NULL,CLSCTX_ALL,&MA_IID_IMMDeviceEnumerator,(Mv**)&pDeviceEnumerator);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
Mr ma_result_from_HRESULT(hr);
}
*ppDeviceEnumerator=pDeviceEnumerator;
Mr Ms;
}
static WCHAR*ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(ma_context*Mc,ma_IMMDeviceEnumerator*pDeviceEnumerator,ma_device_type deviceType)
{
HRESULT hr;
ma_IMMDevice*pMMDefaultDevice=NULL;
WCHAR*pDefaultDeviceID=NULL;
ma_EDataFlow dataFlow;
ma_ERole role;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDeviceEnumerator !=NULL);
(Mv)Mc;
dataFlow=ma_device_type_to_EDataFlow(deviceType);
role=ma_eConsole;
hr=ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator,dataFlow,role,&pMMDefaultDevice);
if (FAILED(hr)) {
Mr NULL;
}
hr=ma_IMMDevice_GetId(pMMDefaultDevice,&pDefaultDeviceID);
ma_IMMDevice_Release(pMMDefaultDevice);
pMMDefaultDevice=NULL;
if (FAILED(hr)) {
Mr NULL;
}
Mr pDefaultDeviceID;
}
static WCHAR*ma_context_get_default_device_id__wasapi(ma_context*Mc,ma_device_type deviceType)
{
Me Mf;
ma_IMMDeviceEnumerator*pDeviceEnumerator;
WCHAR*pDefaultDeviceID=NULL;
MA_ASSERT(Mc !=NULL);
Mf=ma_context_create_IMMDeviceEnumerator__wasapi(Mc,&pDeviceEnumerator);
if (Mf !=Ms) {
Mr NULL;
}
pDefaultDeviceID=ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(Mc,pDeviceEnumerator,deviceType);
ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
Mr pDefaultDeviceID;
}
static Me ma_context_get_MMDevice__wasapi(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_IMMDevice**ppMMDevice)
{
ma_IMMDeviceEnumerator*pDeviceEnumerator;
HRESULT hr;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppMMDevice !=NULL);
ma_CoInitializeEx(Mc,NULL,MA_COINIT_VALUE);
{
hr=ma_CoCreateInstance(Mc,&MA_CLSID_MMDeviceEnumerator,NULL,CLSCTX_ALL,&MA_IID_IMMDeviceEnumerator,(Mv**)&pDeviceEnumerator);
}
ma_CoUninitialize(Mc);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n");
Mr ma_result_from_HRESULT(hr);
}
if (pDeviceID==NULL) {
hr=ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator,(deviceType==ma_device_type_capture)?ma_eCapture:ma_eRender,ma_eConsole,ppMMDevice);
} else {
hr=ma_IMMDeviceEnumerator_GetDevice(pDeviceEnumerator,pDeviceID->wasapi,ppMMDevice);
}
ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.\n");
Mr ma_result_from_HRESULT(hr);
}
Mr Ms;
}
static Me ma_context_get_device_id_from_MMDevice__wasapi(ma_context*Mc,ma_IMMDevice*pMMDevice,ma_device_id*pDeviceID)
{
WCHAR*pDeviceIDString;
HRESULT hr;
MA_ASSERT(pDeviceID !=NULL);
hr=ma_IMMDevice_GetId(pMMDevice,&pDeviceIDString);
if (SUCCEEDED(hr)) {
size_t idlen=ma_strlen_WCHAR(pDeviceIDString);
if (idlen+1>ma_countof(pDeviceID->wasapi)) {
ma_CoTaskMemFree(Mc,pDeviceIDString);
MA_ASSERT(MA_FALSE);
Mr MA_ERROR;
}
MA_COPY_MEMORY(pDeviceID->wasapi,pDeviceIDString,idlen*sizeof(wchar_t));
pDeviceID->wasapi[idlen]='\0';
ma_CoTaskMemFree(Mc,pDeviceIDString);
Mr Ms;
}
Mr MA_ERROR;
}
static Me ma_context_get_device_info_from_MMDevice__wasapi(ma_context*Mc,ma_IMMDevice*pMMDevice,WCHAR*pDefaultDeviceID,ma_bool32 onlySimpleInfo,ma_device_info*pInfo)
{
Me Mf;
HRESULT hr;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pMMDevice !=NULL);
MA_ASSERT(pInfo !=NULL);
Mf=ma_context_get_device_id_from_MMDevice__wasapi(Mc,pMMDevice,&pInfo->id);
if (Mf==Ms) {
if (pDefaultDeviceID !=NULL) {
if (ma_strcmp_WCHAR(pInfo->id.wasapi,pDefaultDeviceID)==0) {
pInfo->isDefault=MA_TRUE;
}
}
}
{
ma_IPropertyStore*pProperties;
hr=ma_IMMDevice_OpenPropertyStore(pMMDevice,STGM_READ,&pProperties);
if (SUCCEEDED(hr)) {
MA_PROPVARIANT var;
ma_PropVariantInit(&var);
hr=ma_IPropertyStore_GetValue(pProperties,&MA_PKEY_Device_FriendlyName,&var);
if (SUCCEEDED(hr)) {
WideCharToMultiByte(CP_UTF8,0,var.pwszVal,-1,pInfo->name,sizeof(pInfo->name),0,FALSE);
ma_PropVariantClear(Mc,&var);
}
ma_IPropertyStore_Release(pProperties);
}
}
if (!onlySimpleInfo) {
ma_IAudioClient*pAudioClient;
hr=ma_IMMDevice_Activate(pMMDevice,&MA_IID_IAudioClient,CLSCTX_ALL,NULL,(Mv**)&pAudioClient);
if (SUCCEEDED(hr)) {
Mf=ma_context_get_device_info_from_IAudioClient__wasapi(Mc,pMMDevice,pAudioClient,pInfo);
ma_IAudioClient_Release(pAudioClient);
Mr Mf;
} else {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.");
Mr ma_result_from_HRESULT(hr);
}
}
Mr Ms;
}
static Me ma_context_enumerate_devices_by_type__wasapi(ma_context*Mc,ma_IMMDeviceEnumerator*pDeviceEnumerator,ma_device_type deviceType,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
Me Mf=Ms;
UINT deviceCount;
HRESULT hr;
M3 iDevice;
WCHAR*pDefaultDeviceID=NULL;
ma_IMMDeviceCollection*pDeviceCollection=NULL;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
pDefaultDeviceID=ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(Mc,pDeviceEnumerator,deviceType);
hr=ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator,ma_device_type_to_EDataFlow(deviceType),MA_MM_DEVICE_STATE_ACTIVE,&pDeviceCollection);
if (SUCCEEDED(hr)) {
hr=ma_IMMDeviceCollection_GetCount(pDeviceCollection,&deviceCount);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.\n");
Mf=ma_result_from_HRESULT(hr);
goto done;
}
for (iDevice=0; iDevice<deviceCount;++iDevice) {
ma_device_info deviceInfo;
ma_IMMDevice*pMMDevice;
MA_ZERO_OBJECT(&deviceInfo);
hr=ma_IMMDeviceCollection_Item(pDeviceCollection,iDevice,&pMMDevice);
if (SUCCEEDED(hr)) {
Mf=ma_context_get_device_info_from_MMDevice__wasapi(Mc,pMMDevice,pDefaultDeviceID,MA_TRUE,&deviceInfo);
ma_IMMDevice_Release(pMMDevice);
if (Mf==Ms) {
 ma_bool32 cbResult=callback(Mc,deviceType,&deviceInfo,pUserData);
 if (cbResult==MA_FALSE) {
 break;
 }
}
}
}
}
done:
if (pDefaultDeviceID !=NULL) {
ma_CoTaskMemFree(Mc,pDefaultDeviceID);
pDefaultDeviceID=NULL;
}
if (pDeviceCollection !=NULL) {
ma_IMMDeviceCollection_Release(pDeviceCollection);
pDeviceCollection=NULL;
}
Mr Mf;
}
static Me ma_context_get_IAudioClient_Desktop__wasapi(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,MA_PROPVARIANT*pActivationParams,ma_IAudioClient**ppAudioClient,ma_IMMDevice**ppMMDevice)
{
Me Mf;
HRESULT hr;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppAudioClient !=NULL);
MA_ASSERT(ppMMDevice !=NULL);
Mf=ma_context_get_MMDevice__wasapi(Mc,deviceType,pDeviceID,ppMMDevice);
if (Mf !=Ms) {
Mr Mf;
}
hr=ma_IMMDevice_Activate(*ppMMDevice,&MA_IID_IAudioClient,CLSCTX_ALL,pActivationParams,(Mv**)ppAudioClient);
if (FAILED(hr)) {
Mr ma_result_from_HRESULT(hr);
}
Mr Ms;
}
#else
static Me ma_context_get_IAudioClient_UWP__wasapi(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,MA_PROPVARIANT*pActivationParams,ma_IAudioClient**ppAudioClient,ma_IUnknown**ppActivatedInterface)
{
ma_IActivateAudioInterfaceAsyncOperation*pAsyncOp=NULL;
ma_completion_handler_uwp completionHandler;
IID iid;
WCHAR*iidStr;
HRESULT hr;
Me Mf;
HRESULT activateResult;
ma_IUnknown*pActivatedInterface;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppAudioClient !=NULL);
if (pDeviceID !=NULL) {
iidStr=(WCHAR*)pDeviceID->wasapi;
} else {
if (deviceType==ma_device_type_capture) {
iid=MA_IID_DEVINTERFACE_AUDIO_CAPTURE;
} else {
iid=MA_IID_DEVINTERFACE_AUDIO_RENDER;
}
#if defined(__cplusplus)
hr=StringFromIID(iid,&iidStr);
#else
hr=StringFromIID(&iid,&iidStr);
#endif
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.\n");
Mr ma_result_from_HRESULT(hr);
}
}
Mf=ma_completion_handler_uwp_init(&completionHandler);
if (Mf !=Ms) {
ma_CoTaskMemFree(Mc,iidStr);
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().\n");
Mr Mf;
}
hr=((MA_PFN_ActivateAudioInterfaceAsync)Mc->wasapi.ActivateAudioInterfaceAsync)(iidStr,&MA_IID_IAudioClient,pActivationParams,(ma_IActivateAudioInterfaceCompletionHandler*)&completionHandler,(ma_IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
if (FAILED(hr)) {
ma_completion_handler_uwp_uninit(&completionHandler);
ma_CoTaskMemFree(Mc,iidStr);
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.\n");
Mr ma_result_from_HRESULT(hr);
}
if (pDeviceID==NULL) {
ma_CoTaskMemFree(Mc,iidStr);
}
ma_completion_handler_uwp_wait(&completionHandler);
ma_completion_handler_uwp_uninit(&completionHandler);
hr=ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp,&activateResult,&pActivatedInterface);
ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);
if (FAILED(hr)||FAILED(activateResult)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.\n");
Mr FAILED(hr)?ma_result_from_HRESULT(hr):ma_result_from_HRESULT(activateResult);
}
hr=ma_IUnknown_QueryInterface(pActivatedInterface,&MA_IID_IAudioClient,(Mv**)ppAudioClient);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.\n");
Mr ma_result_from_HRESULT(hr);
}
if (ppActivatedInterface) {
*ppActivatedInterface=pActivatedInterface;
} else {
ma_IUnknown_Release(pActivatedInterface);
}
Mr Ms;
}
#endif
typedef enum
{
MA_AUDIOCLIENT_ACTIVATION_TYPE_DEFAULT,MA_AUDIOCLIENT_ACTIVATION_TYPE_PROCESS_LOOPBACK
} MA_AUDIOCLIENT_ACTIVATION_TYPE;
typedef enum
{
MA_PROCESS_LOOPBACK_MODE_INCLUDE_TARGET_PROCESS_TREE,MA_PROCESS_LOOPBACK_MODE_EXCLUDE_TARGET_PROCESS_TREE
} MA_PROCESS_LOOPBACK_MODE;
typedef struct
{
DWORD TargetProcessId;
MA_PROCESS_LOOPBACK_MODE ProcessLoopbackMode;
} MA_AUDIOCLIENT_PROCESS_LOOPBACK_PARAMS;
#if defined(_MSC_VER)&&!defined(__clang__)
#pragma warning(push)
#pragma warning(disable:4201)
#elif defined(__clang__)||(defined(__GNUC__)&&(__GNUC__>4||(__GNUC__==4&&__GNUC_MINOR__>=8)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc11-extensions"
#endif
#endif
typedef struct
{
MA_AUDIOCLIENT_ACTIVATION_TYPE ActivationType;
union
{
MA_AUDIOCLIENT_PROCESS_LOOPBACK_PARAMS ProcessLoopbackParams;
};
} MA_AUDIOCLIENT_ACTIVATION_PARAMS;
#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
#endif
#define MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK L"VAD\\Process_Loopback"
static Me ma_context_get_IAudioClient__wasapi(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,M3 loopbackProcessID,ma_bool32 loopbackProcessExclude,ma_IAudioClient**ppAudioClient,ma_WASAPIDeviceInterface**ppDeviceInterface)
{
Me Mf;
ma_bool32 usingProcessLoopback=MA_FALSE;
MA_AUDIOCLIENT_ACTIVATION_PARAMS audioclientActivationParams;
MA_PROPVARIANT activationParams;
MA_PROPVARIANT*pActivationParams=NULL;
ma_device_id virtualDeviceID;
if (deviceType==ma_device_type_loopback&&loopbackProcessID !=0&&pDeviceID==NULL) {
usingProcessLoopback=MA_TRUE;
}
if (usingProcessLoopback) {
MA_ZERO_OBJECT(&audioclientActivationParams);
audioclientActivationParams.ActivationType=MA_AUDIOCLIENT_ACTIVATION_TYPE_PROCESS_LOOPBACK;
audioclientActivationParams.ProcessLoopbackParams.ProcessLoopbackMode=(loopbackProcessExclude)?MA_PROCESS_LOOPBACK_MODE_EXCLUDE_TARGET_PROCESS_TREE:MA_PROCESS_LOOPBACK_MODE_INCLUDE_TARGET_PROCESS_TREE;
audioclientActivationParams.ProcessLoopbackParams.TargetProcessId=(DWORD)loopbackProcessID;
ma_PropVariantInit(&activationParams);
activationParams.vt=MA_VT_BLOB;
activationParams.blob.cbSize=sizeof(audioclientActivationParams);
activationParams.blob.pBlobData=(BYTE*)&audioclientActivationParams;
pActivationParams=&activationParams;
MA_COPY_MEMORY(virtualDeviceID.wasapi,MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK,(wcslen(MA_VIRTUAL_AUDIO_DEVICE_PROCESS_LOOPBACK)+1)*sizeof(wchar_t));
pDeviceID=&virtualDeviceID;
} else {
pActivationParams=NULL;
}
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
Mf=ma_context_get_IAudioClient_Desktop__wasapi(Mc,deviceType,pDeviceID,pActivationParams,ppAudioClient,ppDeviceInterface);
#else
Mf=ma_context_get_IAudioClient_UWP__wasapi(Mc,deviceType,pDeviceID,pActivationParams,ppAudioClient,ppDeviceInterface);
#endif
if (Mf !=Ms) {
if (usingProcessLoopback) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Loopback mode requested to %s process ID %u, but initialization failed. Support for this feature begins with Windows 10 Build 20348. Confirm your version of Windows or consider not using process-specific loopback.\n", (loopbackProcessExclude) ? "exclude" : "include", loopbackProcessID);
}
}
Mr Mf;
}
static Me ma_context_enumerate_devices__wasapi(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
HRESULT hr;
ma_IMMDeviceEnumerator*pDeviceEnumerator;
hr=ma_CoCreateInstance(Mc,&MA_CLSID_MMDeviceEnumerator,NULL,CLSCTX_ALL,&MA_IID_IMMDeviceEnumerator,(Mv**)&pDeviceEnumerator);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
Mr ma_result_from_HRESULT(hr);
}
ma_context_enumerate_devices_by_type__wasapi(Mc,pDeviceEnumerator,Mt,callback,pUserData);
ma_context_enumerate_devices_by_type__wasapi(Mc,pDeviceEnumerator,ma_device_type_capture,callback,pUserData);
ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
#else
if (callback) {
ma_bool32 cbResult=MA_TRUE;
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
deviceInfo.isDefault=MA_TRUE;
cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
}
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
deviceInfo.isDefault=MA_TRUE;
cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
}
#endif
Mr Ms;
}
static Me ma_context_get_device_info__wasapi(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
Me Mf;
ma_IMMDevice*pMMDevice=NULL;
WCHAR*pDefaultDeviceID=NULL;
Mf=ma_context_get_MMDevice__wasapi(Mc,deviceType,pDeviceID,&pMMDevice);
if (Mf !=Ms) {
Mr Mf;
}
pDefaultDeviceID=ma_context_get_default_device_id__wasapi(Mc,deviceType);
Mf=ma_context_get_device_info_from_MMDevice__wasapi(Mc,pMMDevice,pDefaultDeviceID,MA_FALSE,pDeviceInfo);
if (pDefaultDeviceID !=NULL) {
ma_CoTaskMemFree(Mc,pDefaultDeviceID);
pDefaultDeviceID=NULL;
}
ma_IMMDevice_Release(pMMDevice);
Mr Mf;
#else
ma_IAudioClient*pAudioClient;
Me Mf;
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
Mf=ma_context_get_IAudioClient_UWP__wasapi(Mc,deviceType,pDeviceID,NULL,&pAudioClient,NULL);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_context_get_device_info_from_IAudioClient__wasapi(Mc,NULL,pAudioClient,pDeviceInfo);
pDeviceInfo->isDefault=MA_TRUE;
ma_IAudioClient_Release(pAudioClient);
Mr Mf;
#endif
}
static Me ma_device_uninit__wasapi(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
{
if (Md->wasapi.pDeviceEnumerator) {
((ma_IMMDeviceEnumerator*)Md->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)Md->wasapi.pDeviceEnumerator,&Md->wasapi.notificationClient);
ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)Md->wasapi.pDeviceEnumerator);
}
ma_mutex_uninit(&Md->wasapi.rerouteLock);
}
#endif
if (Md->wasapi.pRenderClient) {
if (Md->wasapi.pMappedBufferPlayback !=NULL) {
ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)Md->wasapi.pRenderClient,Md->wasapi.mappedBufferPlaybackCap,0);
Md->wasapi.pMappedBufferPlayback=NULL;
Md->wasapi.mappedBufferPlaybackCap=0;
Md->wasapi.mappedBufferPlaybackLen=0;
}
ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)Md->wasapi.pRenderClient);
}
if (Md->wasapi.pCaptureClient) {
if (Md->wasapi.pMappedBufferCapture !=NULL) {
ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,Md->wasapi.mappedBufferCaptureCap);
Md->wasapi.pMappedBufferCapture=NULL;
Md->wasapi.mappedBufferCaptureCap=0;
Md->wasapi.mappedBufferCaptureLen=0;
}
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient);
}
if (Md->wasapi.pAudioClientPlayback) {
ma_IAudioClient_Release((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback);
}
if (Md->wasapi.pAudioClientCapture) {
ma_IAudioClient_Release((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
}
if (Md->wasapi.hEventPlayback) {
CloseHandle((HANDLE)Md->wasapi.hEventPlayback);
}
if (Md->wasapi.hEventCapture) {
CloseHandle((HANDLE)Md->wasapi.hEventCapture);
}
Mr Ms;
}
typedef struct
{
ma_format formatIn;
M3 channelsIn;
M3 sampleRateIn;
ma_channel channelMapIn[MA_MAX_CHANNELS];
M3 periodSizeInFramesIn;
M3 periodSizeInMillisecondsIn;
M3 periodsIn;
ma_share_mode shareMode;
ma_performance_profile performanceProfile;
ma_bool32 noAutoConvertSRC;
ma_bool32 noDefaultQualitySRC;
ma_bool32 noHardwareOffloading;
M3 loopbackProcessID;
ma_bool32 loopbackProcessExclude;
ma_IAudioClient*pAudioClient;
ma_IAudioRenderClient*pRenderClient;
ma_IAudioCaptureClient*pCaptureClient;
ma_format formatOut;
M3 channelsOut;
M3 sampleRateOut;
ma_channel channelMapOut[MA_MAX_CHANNELS];
M3 periodSizeInFramesOut;
M3 periodsOut;
ma_bool32 usingAudioClient3;
char deviceName[256];
ma_device_id id;
} ma_device_init_internal_data__wasapi;
static Me ma_device_init_internal__wasapi(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_init_internal_data__wasapi*pData)
{
HRESULT hr;
Me Mf=Ms;
const char* errorMsg = "";
MA_AUDCLNT_SHAREMODE shareMode=MA_AUDCLNT_SHAREMODE_SHARED;
DWORD streamFlags=0;
MA_REFERENCE_TIME periodDurationInMicroseconds;
ma_bool32 wasInitializedUsingIAudioClient3=MA_FALSE;
MA_WAVEFORMATEXTENSIBLE wf;
ma_WASAPIDeviceInterface*pDeviceInterface=NULL;
ma_IAudioClient2*pAudioClient2;
M3 nativeSampleRate;
ma_bool32 usingProcessLoopback=MA_FALSE;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pData !=NULL);
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
usingProcessLoopback=deviceType==ma_device_type_loopback&&pData->loopbackProcessID !=0&&pDeviceID==NULL;
pData->pAudioClient=NULL;
pData->pRenderClient=NULL;
pData->pCaptureClient=NULL;
streamFlags=MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
if (!pData->noAutoConvertSRC&&pData->sampleRateIn !=0&&pData->shareMode !=ma_share_mode_exclusive) {
streamFlags|=MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
}
if (!pData->noDefaultQualitySRC&&pData->sampleRateIn !=0&&(streamFlags&MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) !=0) {
streamFlags|=MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
}
if (deviceType==ma_device_type_loopback) {
streamFlags|=MA_AUDCLNT_STREAMFLAGS_LOOPBACK;
}
Mf=ma_context_get_IAudioClient__wasapi(Mc,deviceType,pDeviceID,pData->loopbackProcessID,pData->loopbackProcessExclude,&pData->pAudioClient,&pDeviceInterface);
if (Mf !=Ms) {
goto done;
}
MA_ZERO_OBJECT(&wf);
if (!pData->noHardwareOffloading) {
hr=ma_IAudioClient_QueryInterface(pData->pAudioClient,&MA_IID_IAudioClient2,(Mv**)&pAudioClient2);
if (SUCCEEDED(hr)) {
BOOL isHardwareOffloadingSupported=0;
hr=ma_IAudioClient2_IsOffloadCapable(pAudioClient2,MA_AudioCategory_Other,&isHardwareOffloadingSupported);
if (SUCCEEDED(hr)&&isHardwareOffloadingSupported) {
ma_AudioClientProperties clientProperties;
MA_ZERO_OBJECT(&clientProperties);
clientProperties.cbSize=sizeof(clientProperties);
clientProperties.bIsOffload=1;
clientProperties.eCategory=MA_AudioCategory_Other;
ma_IAudioClient2_SetClientProperties(pAudioClient2,&clientProperties);
}
pAudioClient2->lpVtbl->Release(pAudioClient2);
}
}
Mf=MA_FORMAT_NOT_SUPPORTED;
if (pData->shareMode==ma_share_mode_exclusive) {
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
ma_IPropertyStore*pStore=NULL;
hr=ma_IMMDevice_OpenPropertyStore(pDeviceInterface,STGM_READ,&pStore);
if (SUCCEEDED(hr)) {
MA_PROPVARIANT prop;
ma_PropVariantInit(&prop);
hr=ma_IPropertyStore_GetValue(pStore,&MA_PKEY_AudioEngine_DeviceFormat,&prop);
if (SUCCEEDED(hr)) {
MA_WAVEFORMATEX*pActualFormat=(MA_WAVEFORMATEX*)prop.blob.pBlobData;
hr=ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient,MA_AUDCLNT_SHAREMODE_EXCLUSIVE,pActualFormat,NULL);
if (SUCCEEDED(hr)) {
 MA_COPY_MEMORY(&wf,pActualFormat,sizeof(MA_WAVEFORMATEXTENSIBLE));
}
ma_PropVariantClear(Mc,&prop);
}
ma_IPropertyStore_Release(pStore);
}
#else
hr=S_FALSE;
#endif
if (hr==S_OK) {
shareMode=MA_AUDCLNT_SHAREMODE_EXCLUSIVE;
Mf=Ms;
} else {
Mf=MA_SHARE_MODE_NOT_SUPPORTED;
}
} else {
MA_WAVEFORMATEXTENSIBLE*pNativeFormat=NULL;
hr=ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient,(MA_WAVEFORMATEX**)&pNativeFormat);
if (hr !=S_OK) {
if (usingProcessLoopback) {
wf.wFormatTag=WAVE_FORMAT_IEEE_FLOAT;
wf.nChannels=2;
wf.nSamplesPerSec=44100;
wf.wBitsPerSample=32;
wf.nBlockAlign=wf.nChannels*wf.wBitsPerSample / 8;
wf.nAvgBytesPerSec=wf.nSamplesPerSec*wf.nBlockAlign;
wf.cbSize=sizeof(MA_WAVEFORMATEX);
Mf=Ms;
} else {
Mf=MA_FORMAT_NOT_SUPPORTED;
}
} else {
if (pNativeFormat->wFormatTag==WAVE_FORMAT_EXTENSIBLE) {
MA_COPY_MEMORY(&wf,pNativeFormat,sizeof(MA_WAVEFORMATEXTENSIBLE));
} else {
size_t cbSize=pNativeFormat->cbSize;
if (cbSize==0) {
 cbSize=sizeof(MA_WAVEFORMATEX);
}
if (cbSize>sizeof(wf)) {
 cbSize=sizeof(wf);
}
MA_COPY_MEMORY(&wf,pNativeFormat,cbSize);
}
Mf=Ms;
}
ma_CoTaskMemFree(Mc,pNativeFormat);
shareMode=MA_AUDCLNT_SHAREMODE_SHARED;
}
if (Mf !=Ms) {
errorMsg = "[WASAPI] Failed to find best device mix format.";
goto done;
}
nativeSampleRate=wf.nSamplesPerSec;
if (streamFlags&MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) {
wf.nSamplesPerSec=(pData->sampleRateIn !=0)?pData->sampleRateIn:MA_DEFAULT_SAMPLE_RATE;
wf.nAvgBytesPerSec=wf.nSamplesPerSec*wf.nBlockAlign;
}
pData->formatOut=ma_format_from_WAVEFORMATEX((MA_WAVEFORMATEX*)&wf);
if (pData->formatOut==ma_format_unknown) {
if (shareMode==MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
Mf=MA_SHARE_MODE_NOT_SUPPORTED;
} else {
Mf=MA_FORMAT_NOT_SUPPORTED;
}
errorMsg = "[WASAPI] Native format not supported.";
goto done;
}
pData->channelsOut=wf.nChannels;
pData->sampleRateOut=wf.nSamplesPerSec;
if (wf.wFormatTag==WAVE_FORMAT_EXTENSIBLE||wf.cbSize>=sizeof(MA_WAVEFORMATEXTENSIBLE)) {
ma_channel_mask_to_channel_map__win32(wf.dwChannelMask,pData->channelsOut,pData->channelMapOut);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_microsoft,pData->channelMapOut,ma_countof(pData->channelMapOut),pData->channelsOut);
}
pData->periodsOut=(pData->periodsIn !=0)?pData->periodsIn:MA_DEFAULT_PERIODS;
pData->periodSizeInFramesOut=pData->periodSizeInFramesIn;
if (pData->periodSizeInFramesOut==0) {
if (pData->periodSizeInMillisecondsIn==0) {
if (pData->performanceProfile==ma_performance_profile_low_latency) {
pData->periodSizeInFramesOut=ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY,wf.nSamplesPerSec);
} else {
pData->periodSizeInFramesOut=ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE,wf.nSamplesPerSec);
}
} else {
pData->periodSizeInFramesOut=ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn,wf.nSamplesPerSec);
}
}
periodDurationInMicroseconds=((M6)pData->periodSizeInFramesOut*1000*1000) / wf.nSamplesPerSec;
if (shareMode==MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
MA_REFERENCE_TIME bufferDuration=periodDurationInMicroseconds*pData->periodsOut*10;
hr=E_FAIL;
for (;;) {
hr=ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient,shareMode,streamFlags,bufferDuration,bufferDuration,(MA_WAVEFORMATEX*)&wf,NULL);
if (hr==MA_AUDCLNT_E_INVALID_DEVICE_PERIOD) {
if (bufferDuration>500*10000) {
 break;
} else {
 if (bufferDuration==0) {
 break;
 }
 bufferDuration=bufferDuration*2;
 continue;
}
} else {
break;
}
}
if (hr==MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
M3 bufferSizeInFrames;
hr=ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient,&bufferSizeInFrames);
if (SUCCEEDED(hr)) {
bufferDuration=(MA_REFERENCE_TIME)((10000.0*1000 / wf.nSamplesPerSec*bufferSizeInFrames)+0.5);
ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
hr=ma_IMMDevice_Activate(pDeviceInterface,&MA_IID_IAudioClient,CLSCTX_ALL,NULL,(Mv**)&pData->pAudioClient);
#else
hr=ma_IUnknown_QueryInterface(pDeviceInterface,&MA_IID_IAudioClient,(Mv**)&pData->pAudioClient);
#endif
if (SUCCEEDED(hr)) {
 hr=ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient,shareMode,streamFlags,bufferDuration,bufferDuration,(MA_WAVEFORMATEX*)&wf,NULL);
}
}
}
if (FAILED(hr)) {
if (hr==E_ACCESSDENIED) {
errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Access denied.", Mf = MA_ACCESS_DENIED;
} else if (hr==MA_AUDCLNT_E_DEVICE_IN_USE) {
errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Device in use.", Mf = MA_BUSY;
} else {
errorMsg = "[WASAPI] Failed to initialize device in exclusive mode."; Mf = ma_result_from_HRESULT(hr);
}
goto done;
}
}
if (shareMode==MA_AUDCLNT_SHAREMODE_SHARED) {
#ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE
{
if ((streamFlags&MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)==0||nativeSampleRate==wf.nSamplesPerSec) {
ma_IAudioClient3*pAudioClient3=NULL;
hr=ma_IAudioClient_QueryInterface(pData->pAudioClient,&MA_IID_IAudioClient3,(Mv**)&pAudioClient3);
if (SUCCEEDED(hr)) {
 M3 defaultPeriodInFrames;
 M3 fundamentalPeriodInFrames;
 M3 minPeriodInFrames;
 M3 maxPeriodInFrames;
 hr=ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3,(MA_WAVEFORMATEX*)&wf,&defaultPeriodInFrames,&fundamentalPeriodInFrames,&minPeriodInFrames,&maxPeriodInFrames);
 if (SUCCEEDED(hr)) {
 M3 desiredPeriodInFrames=pData->periodSizeInFramesOut;
 M3 actualPeriodInFrames=desiredPeriodInFrames;
 actualPeriodInFrames=actualPeriodInFrames / fundamentalPeriodInFrames;
 actualPeriodInFrames=actualPeriodInFrames*fundamentalPeriodInFrames;
 actualPeriodInFrames=ma_clamp(actualPeriodInFrames,minPeriodInFrames,maxPeriodInFrames);
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames);
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " defaultPeriodInFrames=%d\n", defaultPeriodInFrames);
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames);
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " minPeriodInFrames=%d\n", minPeriodInFrames);
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " maxPeriodInFrames=%d\n", maxPeriodInFrames);
 if (actualPeriodInFrames>=desiredPeriodInFrames) {
 hr=ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3,streamFlags&~(MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY),actualPeriodInFrames,(MA_WAVEFORMATEX*)&wf,NULL);
 if (SUCCEEDED(hr)) {
 wasInitializedUsingIAudioClient3=MA_TRUE;
 pData->periodSizeInFramesOut=actualPeriodInFrames;
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n");
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut);
 } else {
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n");
 }
 } else {
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[WASAPI] Not using IAudioClient3 because the desired period size is larger than the maximum supported by IAudioClient3.\n");
 }
 } else {
 ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n");
 }
 ma_IAudioClient3_Release(pAudioClient3);
 pAudioClient3=NULL;
}
}
}
#else
{
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[WASAPI] Not using IAudioClient3 because MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE is enabled.\n");
}
#endif
if (!wasInitializedUsingIAudioClient3) {
MA_REFERENCE_TIME bufferDuration=periodDurationInMicroseconds*pData->periodsOut*10;
hr=ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient,shareMode,streamFlags,bufferDuration,0,(const MA_WAVEFORMATEX*)&wf,NULL);
if (FAILED(hr)) {
if (hr==E_ACCESSDENIED) {
 errorMsg = "[WASAPI] Failed to initialize device. Access denied.", Mf = MA_ACCESS_DENIED;
} else if (hr==MA_AUDCLNT_E_DEVICE_IN_USE) {
 errorMsg = "[WASAPI] Failed to initialize device. Device in use.", Mf = MA_BUSY;
} else {
 errorMsg = "[WASAPI] Failed to initialize device.", Mf = ma_result_from_HRESULT(hr);
}
goto done;
}
}
}
if (!wasInitializedUsingIAudioClient3) {
M3 bufferSizeInFrames=0;
hr=ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient,&bufferSizeInFrames);
if (FAILED(hr)) {
errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", Mf = ma_result_from_HRESULT(hr);
goto done;
}
if (usingProcessLoopback) {
bufferSizeInFrames=(M3)((periodDurationInMicroseconds*pData->periodsOut)*pData->sampleRateOut / 1000000);
}
pData->periodSizeInFramesOut=bufferSizeInFrames / pData->periodsOut;
}
pData->usingAudioClient3=wasInitializedUsingIAudioClient3;
if (deviceType==Mt) {
Mf=ma_device_create_IAudioClient_service__wasapi(Mc,deviceType,(ma_IAudioClient*)pData->pAudioClient,(Mv**)&pData->pRenderClient);
} else {
Mf=ma_device_create_IAudioClient_service__wasapi(Mc,deviceType,(ma_IAudioClient*)pData->pAudioClient,(Mv**)&pData->pCaptureClient);
}
if (Mf !=Ms) {
errorMsg = "[WASAPI] Failed to get audio client service.";
goto done;
}
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
{
ma_IPropertyStore*pProperties;
hr=ma_IMMDevice_OpenPropertyStore(pDeviceInterface,STGM_READ,&pProperties);
if (SUCCEEDED(hr)) {
MA_PROPVARIANT varName;
ma_PropVariantInit(&varName);
hr=ma_IPropertyStore_GetValue(pProperties,&MA_PKEY_Device_FriendlyName,&varName);
if (SUCCEEDED(hr)) {
WideCharToMultiByte(CP_UTF8,0,varName.pwszVal,-1,pData->deviceName,sizeof(pData->deviceName),0,FALSE);
ma_PropVariantClear(Mc,&varName);
}
ma_IPropertyStore_Release(pProperties);
}
}
#endif
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
{
ma_context_get_device_id_from_MMDevice__wasapi(Mc,pDeviceInterface,&pData->id);
}
#else
{
}
#endif
done:
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
if (pDeviceInterface !=NULL) {
ma_IMMDevice_Release(pDeviceInterface);
}
#else
if (pDeviceInterface !=NULL) {
ma_IUnknown_Release(pDeviceInterface);
}
#endif
if (Mf !=Ms) {
if (pData->pRenderClient) {
ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pData->pRenderClient);
pData->pRenderClient=NULL;
}
if (pData->pCaptureClient) {
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pData->pCaptureClient);
pData->pCaptureClient=NULL;
}
if (pData->pAudioClient) {
ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
pData->pAudioClient=NULL;
}
if (errorMsg !=NULL&&errorMsg[0] !='\0') {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "%s\n", errorMsg);
}
Mr Mf;
} else {
Mr Ms;
}
}
static Me ma_device_reinit__wasapi(ma_device*Md,ma_device_type deviceType)
{
ma_device_init_internal_data__wasapi data;
Me Mf;
MA_ASSERT(Md !=NULL);
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_loopback) {
if (Md->wasapi.pCaptureClient) {
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient);
Md->wasapi.pCaptureClient=NULL;
}
if (Md->wasapi.pAudioClientCapture) {
Md->wasapi.pAudioClientCapture=NULL;
}
}
if (deviceType==Mt) {
if (Md->wasapi.pRenderClient) {
ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)Md->wasapi.pRenderClient);
Md->wasapi.pRenderClient=NULL;
}
if (Md->wasapi.pAudioClientPlayback) {
Md->wasapi.pAudioClientPlayback=NULL;
}
}
if (deviceType==Mt) {
data.formatIn=Md->playback.format;
data.channelsIn=Md->playback.Mh;
MA_COPY_MEMORY(data.channelMapIn,Md->playback.channelMap,sizeof(Md->playback.channelMap));
data.shareMode=Md->playback.shareMode;
} else {
data.formatIn=Md->capture.format;
data.channelsIn=Md->capture.Mh;
MA_COPY_MEMORY(data.channelMapIn,Md->capture.channelMap,sizeof(Md->capture.channelMap));
data.shareMode=Md->capture.shareMode;
}
data.sampleRateIn=Md->sampleRate;
data.periodSizeInFramesIn=Md->wasapi.originalPeriodSizeInFrames;
data.periodSizeInMillisecondsIn=Md->wasapi.originalPeriodSizeInMilliseconds;
data.periodsIn=Md->wasapi.originalPeriods;
data.performanceProfile=Md->wasapi.originalPerformanceProfile;
data.noAutoConvertSRC=Md->wasapi.noAutoConvertSRC;
data.noDefaultQualitySRC=Md->wasapi.noDefaultQualitySRC;
data.noHardwareOffloading=Md->wasapi.noHardwareOffloading;
data.loopbackProcessID=Md->wasapi.loopbackProcessID;
data.loopbackProcessExclude=Md->wasapi.loopbackProcessExclude;
Mf=ma_device_init_internal__wasapi(Md->Mc,deviceType,NULL,&data);
if (Mf !=Ms) {
Mr Mf;
}
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_loopback) {
Md->wasapi.pAudioClientCapture=data.pAudioClient;
Md->wasapi.pCaptureClient=data.pCaptureClient;
Md->capture.internalFormat=data.formatOut;
Md->capture.internalChannels=data.channelsOut;
Md->capture.internalSampleRate=data.sampleRateOut;
MA_COPY_MEMORY(Md->capture.internalChannelMap,data.channelMapOut,sizeof(data.channelMapOut));
Md->capture.internalPeriodSizeInFrames=data.periodSizeInFramesOut;
Md->capture.internalPeriods=data.periodsOut;
ma_strcpy_s(Md->capture.name,sizeof(Md->capture.name),data.deviceName);
ma_IAudioClient_SetEventHandle((ma_IAudioClient*)Md->wasapi.pAudioClientCapture,(HANDLE)Md->wasapi.hEventCapture);
Md->wasapi.periodSizeInFramesCapture=data.periodSizeInFramesOut;
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)Md->wasapi.pAudioClientCapture,&Md->wasapi.actualBufferSizeInFramesCapture);
ma_strcpy_s_WCHAR(Md->capture.id.wasapi,sizeof(Md->capture.id.wasapi),data.id.wasapi);
}
if (deviceType==Mt) {
Md->wasapi.pAudioClientPlayback=data.pAudioClient;
Md->wasapi.pRenderClient=data.pRenderClient;
Md->playback.internalFormat=data.formatOut;
Md->playback.internalChannels=data.channelsOut;
Md->playback.internalSampleRate=data.sampleRateOut;
MA_COPY_MEMORY(Md->playback.internalChannelMap,data.channelMapOut,sizeof(data.channelMapOut));
Md->playback.internalPeriodSizeInFrames=data.periodSizeInFramesOut;
Md->playback.internalPeriods=data.periodsOut;
ma_strcpy_s(Md->playback.name,sizeof(Md->playback.name),data.deviceName);
ma_IAudioClient_SetEventHandle((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback,(HANDLE)Md->wasapi.hEventPlayback);
Md->wasapi.periodSizeInFramesPlayback=data.periodSizeInFramesOut;
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback,&Md->wasapi.actualBufferSizeInFramesPlayback);
ma_strcpy_s_WCHAR(Md->playback.id.wasapi,sizeof(Md->playback.id.wasapi),data.id.wasapi);
}
Mr Ms;
}
static Me ma_device_init__wasapi(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf=Ms;
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
HRESULT hr;
ma_IMMDeviceEnumerator*pDeviceEnumerator;
#endif
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->wasapi);
Md->wasapi.usage=Mo->wasapi.usage;
Md->wasapi.noAutoConvertSRC=Mo->wasapi.noAutoConvertSRC;
Md->wasapi.noDefaultQualitySRC=Mo->wasapi.noDefaultQualitySRC;
Md->wasapi.noHardwareOffloading=Mo->wasapi.noHardwareOffloading;
Md->wasapi.loopbackProcessID=Mo->wasapi.loopbackProcessID;
Md->wasapi.loopbackProcessExclude=Mo->wasapi.loopbackProcessExclude;
if (Mo->deviceType==ma_device_type_loopback&&Mo->playback.shareMode==ma_share_mode_exclusive) {
Mr MA_INVALID_DEVICE_CONFIG;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex||Mo->deviceType==ma_device_type_loopback) {
ma_device_init_internal_data__wasapi data;
data.formatIn=pDescriptorCapture->format;
data.channelsIn=pDescriptorCapture->Mh;
data.sampleRateIn=pDescriptorCapture->sampleRate;
MA_COPY_MEMORY(data.channelMapIn,pDescriptorCapture->channelMap,sizeof(pDescriptorCapture->channelMap));
data.periodSizeInFramesIn=pDescriptorCapture->periodSizeInFrames;
data.periodSizeInMillisecondsIn=pDescriptorCapture->periodSizeInMilliseconds;
data.periodsIn=pDescriptorCapture->periodCount;
data.shareMode=pDescriptorCapture->shareMode;
data.performanceProfile=Mo->performanceProfile;
data.noAutoConvertSRC=Mo->wasapi.noAutoConvertSRC;
data.noDefaultQualitySRC=Mo->wasapi.noDefaultQualitySRC;
data.noHardwareOffloading=Mo->wasapi.noHardwareOffloading;
data.loopbackProcessID=Mo->wasapi.loopbackProcessID;
data.loopbackProcessExclude=Mo->wasapi.loopbackProcessExclude;
Mf=ma_device_init_internal__wasapi(Md->Mc,(Mo->deviceType==ma_device_type_loopback)?ma_device_type_loopback:ma_device_type_capture,pDescriptorCapture->pDeviceID,&data);
if (Mf !=Ms) {
Mr Mf;
}
Md->wasapi.pAudioClientCapture=data.pAudioClient;
Md->wasapi.pCaptureClient=data.pCaptureClient;
Md->wasapi.originalPeriodSizeInMilliseconds=pDescriptorCapture->periodSizeInMilliseconds;
Md->wasapi.originalPeriodSizeInFrames=pDescriptorCapture->periodSizeInFrames;
Md->wasapi.originalPeriods=pDescriptorCapture->periodCount;
Md->wasapi.originalPerformanceProfile=Mo->performanceProfile;
Md->wasapi.hEventCapture=(ma_handle)CreateEventA(NULL,FALSE,FALSE,NULL);
if (Md->wasapi.hEventCapture==NULL) {
Mf=ma_result_from_GetLastError(GetLastError());
if (Md->wasapi.pCaptureClient !=NULL) {
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient);
Md->wasapi.pCaptureClient=NULL;
}
if (Md->wasapi.pAudioClientCapture !=NULL) {
ma_IAudioClient_Release((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
Md->wasapi.pAudioClientCapture=NULL;
}
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.");
Mr Mf;
}
ma_IAudioClient_SetEventHandle((ma_IAudioClient*)Md->wasapi.pAudioClientCapture,(HANDLE)Md->wasapi.hEventCapture);
Md->wasapi.periodSizeInFramesCapture=data.periodSizeInFramesOut;
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)Md->wasapi.pAudioClientCapture,&Md->wasapi.actualBufferSizeInFramesCapture);
ma_strcpy_s_WCHAR(Md->capture.id.wasapi,sizeof(Md->capture.id.wasapi),data.id.wasapi);
pDescriptorCapture->format=data.formatOut;
pDescriptorCapture->Mh=data.channelsOut;
pDescriptorCapture->sampleRate=data.sampleRateOut;
MA_COPY_MEMORY(pDescriptorCapture->channelMap,data.channelMapOut,sizeof(data.channelMapOut));
pDescriptorCapture->periodSizeInFrames=data.periodSizeInFramesOut;
pDescriptorCapture->periodCount=data.periodsOut;
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
ma_device_init_internal_data__wasapi data;
data.formatIn=Mp->format;
data.channelsIn=Mp->Mh;
data.sampleRateIn=Mp->sampleRate;
MA_COPY_MEMORY(data.channelMapIn,Mp->channelMap,sizeof(Mp->channelMap));
data.periodSizeInFramesIn=Mp->periodSizeInFrames;
data.periodSizeInMillisecondsIn=Mp->periodSizeInMilliseconds;
data.periodsIn=Mp->periodCount;
data.shareMode=Mp->shareMode;
data.performanceProfile=Mo->performanceProfile;
data.noAutoConvertSRC=Mo->wasapi.noAutoConvertSRC;
data.noDefaultQualitySRC=Mo->wasapi.noDefaultQualitySRC;
data.noHardwareOffloading=Mo->wasapi.noHardwareOffloading;
data.loopbackProcessID=Mo->wasapi.loopbackProcessID;
data.loopbackProcessExclude=Mo->wasapi.loopbackProcessExclude;
Mf=ma_device_init_internal__wasapi(Md->Mc,Mt,Mp->pDeviceID,&data);
if (Mf !=Ms) {
if (Mo->deviceType==ma_device_type_duplex) {
if (Md->wasapi.pCaptureClient !=NULL) {
 ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient);
 Md->wasapi.pCaptureClient=NULL;
}
if (Md->wasapi.pAudioClientCapture !=NULL) {
 ma_IAudioClient_Release((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
 Md->wasapi.pAudioClientCapture=NULL;
}
CloseHandle((HANDLE)Md->wasapi.hEventCapture);
Md->wasapi.hEventCapture=NULL;
}
Mr Mf;
}
Md->wasapi.pAudioClientPlayback=data.pAudioClient;
Md->wasapi.pRenderClient=data.pRenderClient;
Md->wasapi.originalPeriodSizeInMilliseconds=Mp->periodSizeInMilliseconds;
Md->wasapi.originalPeriodSizeInFrames=Mp->periodSizeInFrames;
Md->wasapi.originalPeriods=Mp->periodCount;
Md->wasapi.originalPerformanceProfile=Mo->performanceProfile;
Md->wasapi.hEventPlayback=(ma_handle)CreateEventA(NULL,FALSE,TRUE,NULL);
if (Md->wasapi.hEventPlayback==NULL) {
Mf=ma_result_from_GetLastError(GetLastError());
if (Mo->deviceType==ma_device_type_duplex) {
if (Md->wasapi.pCaptureClient !=NULL) {
 ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient);
 Md->wasapi.pCaptureClient=NULL;
}
if (Md->wasapi.pAudioClientCapture !=NULL) {
 ma_IAudioClient_Release((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
 Md->wasapi.pAudioClientCapture=NULL;
}
CloseHandle((HANDLE)Md->wasapi.hEventCapture);
Md->wasapi.hEventCapture=NULL;
}
if (Md->wasapi.pRenderClient !=NULL) {
ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)Md->wasapi.pRenderClient);
Md->wasapi.pRenderClient=NULL;
}
if (Md->wasapi.pAudioClientPlayback !=NULL) {
ma_IAudioClient_Release((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback);
Md->wasapi.pAudioClientPlayback=NULL;
}
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.");
Mr Mf;
}
ma_IAudioClient_SetEventHandle((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback,(HANDLE)Md->wasapi.hEventPlayback);
Md->wasapi.periodSizeInFramesPlayback=data.periodSizeInFramesOut;
ma_IAudioClient_GetBufferSize((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback,&Md->wasapi.actualBufferSizeInFramesPlayback);
ma_strcpy_s_WCHAR(Md->playback.id.wasapi,sizeof(Md->playback.id.wasapi),data.id.wasapi);
Mp->format=data.formatOut;
Mp->Mh=data.channelsOut;
Mp->sampleRate=data.sampleRateOut;
MA_COPY_MEMORY(Mp->channelMap,data.channelMapOut,sizeof(data.channelMapOut));
Mp->periodSizeInFrames=data.periodSizeInFramesOut;
Mp->periodCount=data.periodsOut;
}
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
if (Mo->wasapi.noAutoStreamRouting==MA_FALSE) {
if ((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex||Mo->deviceType==ma_device_type_loopback)&&Mo->capture.pDeviceID==NULL) {
Md->wasapi.allowCaptureAutoStreamRouting=MA_TRUE;
}
if ((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mo->playback.pDeviceID==NULL) {
Md->wasapi.allowPlaybackAutoStreamRouting=MA_TRUE;
}
}
ma_mutex_init(&Md->wasapi.rerouteLock);
hr=ma_CoCreateInstance(Md->Mc,&MA_CLSID_MMDeviceEnumerator,NULL,CLSCTX_ALL,&MA_IID_IMMDeviceEnumerator,(Mv**)&pDeviceEnumerator);
if (FAILED(hr)) {
ma_device_uninit__wasapi(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
Mr ma_result_from_HRESULT(hr);
}
Md->wasapi.notificationClient.lpVtbl=(Mv*)&g_maNotificationCientVtbl;
Md->wasapi.notificationClient.counter=1;
Md->wasapi.notificationClient.Md=Md;
hr=pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator,&Md->wasapi.notificationClient);
if (SUCCEEDED(hr)) {
Md->wasapi.pDeviceEnumerator=(ma_ptr)pDeviceEnumerator;
} else {
ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
}
#endif
ma_atomic_bool32_set(&Md->wasapi.isStartedCapture,MA_FALSE);
ma_atomic_bool32_set(&Md->wasapi.isStartedPlayback,MA_FALSE);
Mr Ms;
}
static Me ma_device__get_available_frames__wasapi(ma_device*Md,ma_IAudioClient*pAudioClient,M3*pFrameCount)
{
M3 paddingFramesCount;
HRESULT hr;
ma_share_mode shareMode;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pFrameCount !=NULL);
*pFrameCount=0;
if ((ma_ptr)pAudioClient !=Md->wasapi.pAudioClientPlayback&&(ma_ptr)pAudioClient !=Md->wasapi.pAudioClientCapture) {
Mr MA_INVALID_OPERATION;
}
shareMode=((ma_ptr)pAudioClient==Md->wasapi.pAudioClientPlayback)?Md->playback.shareMode:Md->capture.shareMode;
if (shareMode==ma_share_mode_shared) {
hr=ma_IAudioClient_GetCurrentPadding(pAudioClient,&paddingFramesCount);
if (FAILED(hr)) {
Mr ma_result_from_HRESULT(hr);
}
if ((ma_ptr)pAudioClient==Md->wasapi.pAudioClientPlayback) {
*pFrameCount=Md->wasapi.actualBufferSizeInFramesPlayback-paddingFramesCount;
} else {
*pFrameCount=paddingFramesCount;
}
} else {
if ((ma_ptr)pAudioClient==Md->wasapi.pAudioClientPlayback) {
*pFrameCount=Md->wasapi.actualBufferSizeInFramesPlayback;
} else {
*pFrameCount=Md->wasapi.actualBufferSizeInFramesCapture;
}
}
Mr Ms;
}
static Me ma_device_reroute__wasapi(ma_device*Md,ma_device_type deviceType)
{
Me Mf;
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "=== CHANGING DEVICE ===\n");
Mf=ma_device_reinit__wasapi(Md,deviceType);
if (Mf !=Ms) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[WASAPI] Reinitializing device after route change failed.\n");
Mr Mf;
}
ma_device__post_init_setup(Md,deviceType);
ma_device__on_notification_rerouted(Md);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "=== DEVICE CHANGED ===\n");
Mr Ms;
}
static Me ma_device_start__wasapi_nolock(ma_device*Md)
{
HRESULT hr;
if (Md->Mc->wasapi.hAvrt) {
const char*pTaskName=ma_to_usage_string__wasapi(Md->wasapi.usage);
if (pTaskName) {
DWORD idx=0;
Md->wasapi.hAvrtHandle=(ma_handle)((MA_PFN_AvSetMmThreadCharacteristicsA)Md->Mc->wasapi.AvSetMmThreadCharacteristicsA)(pTaskName,&idx);
}
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex||Md->type==ma_device_type_loopback) {
hr=ma_IAudioClient_Start((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
if (FAILED(hr)) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device. HRESULT = %d.", (int)hr);
Mr ma_result_from_HRESULT(hr);
}
ma_atomic_bool32_set(&Md->wasapi.isStartedCapture,MA_TRUE);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
hr=ma_IAudioClient_Start((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback);
if (FAILED(hr)) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device. HRESULT = %d.", (int)hr);
Mr ma_result_from_HRESULT(hr);
}
ma_atomic_bool32_set(&Md->wasapi.isStartedPlayback,MA_TRUE);
}
Mr Ms;
}
static Me ma_device_start__wasapi(ma_device*Md)
{
Me Mf;
MA_ASSERT(Md !=NULL);
ma_mutex_lock(&Md->wasapi.rerouteLock);
{
Mf=ma_device_start__wasapi_nolock(Md);
}
ma_mutex_unlock(&Md->wasapi.rerouteLock);
Mr Mf;
}
static Me ma_device_stop__wasapi_nolock(ma_device*Md)
{
Me Mf;
HRESULT hr;
MA_ASSERT(Md !=NULL);
if (Md->wasapi.hAvrtHandle) {
((MA_PFN_AvRevertMmThreadCharacteristics)Md->Mc->wasapi.AvRevertMmThreadcharacteristics)((HANDLE)Md->wasapi.hAvrtHandle);
Md->wasapi.hAvrtHandle=NULL;
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex||Md->type==ma_device_type_loopback) {
if (Md->wasapi.pMappedBufferCapture !=NULL) {
ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,Md->wasapi.mappedBufferCaptureCap);
Md->wasapi.pMappedBufferCapture=NULL;
Md->wasapi.mappedBufferCaptureCap=0;
Md->wasapi.mappedBufferCaptureLen=0;
}
hr=ma_IAudioClient_Stop((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.");
Mr ma_result_from_HRESULT(hr);
}
hr=ma_IAudioClient_Reset((ma_IAudioClient*)Md->wasapi.pAudioClientCapture);
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.");
Mr ma_result_from_HRESULT(hr);
}
ma_atomic_bool32_set(&Md->wasapi.isStartedCapture,MA_FALSE);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
if (Md->wasapi.pMappedBufferPlayback !=NULL) {
ma_silence_pcm_frames(
ma_offset_pcm_frames_ptr(Md->wasapi.pMappedBufferPlayback,Md->wasapi.mappedBufferPlaybackLen,Md->playback.internalFormat,Md->playback.internalChannels),Md->wasapi.mappedBufferPlaybackCap-Md->wasapi.mappedBufferPlaybackLen,Md->playback.internalFormat,Md->playback.internalChannels
);
ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)Md->wasapi.pRenderClient,Md->wasapi.mappedBufferPlaybackCap,0);
Md->wasapi.pMappedBufferPlayback=NULL;
Md->wasapi.mappedBufferPlaybackCap=0;
Md->wasapi.mappedBufferPlaybackLen=0;
}
if (ma_atomic_bool32_get(&Md->wasapi.isStartedPlayback)) {
DWORD waitTime=(Md->wasapi.actualBufferSizeInFramesPlayback*1000) / Md->playback.internalSampleRate;
if (Md->playback.shareMode==ma_share_mode_exclusive) {
WaitForSingleObject((HANDLE)Md->wasapi.hEventPlayback,waitTime);
} else {
M3 prevFramesAvailablePlayback=(M3)-1;
M3 framesAvailablePlayback;
for (;;) {
 Mf=ma_device__get_available_frames__wasapi(Md,(ma_IAudioClient*)Md->wasapi.pAudioClientPlayback,&framesAvailablePlayback);
 if (Mf !=Ms) {
 break;
 }
 if (framesAvailablePlayback>=Md->wasapi.actualBufferSizeInFramesPlayback) {
 break;
 }
 if (framesAvailablePlayback==prevFramesAvailablePlayback) {
 break;
 }
 prevFramesAvailablePlayback=framesAvailablePlayback;
 ResetEvent((HANDLE)Md->wasapi.hEventPlayback);
 WaitForSingleObject((HANDLE)Md->wasapi.hEventPlayback,waitTime);
}
}
}
hr=ma_IAudioClient_Stop((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback);
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.");
Mr ma_result_from_HRESULT(hr);
}
{
ma_int32 retries=5;
while ((hr=ma_IAudioClient_Reset((ma_IAudioClient*)Md->wasapi.pAudioClientPlayback))==MA_AUDCLNT_E_BUFFER_OPERATION_PENDING&&retries>0) {
ma_sleep(10);
retries-=1;
}
}
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.");
Mr ma_result_from_HRESULT(hr);
}
ma_atomic_bool32_set(&Md->wasapi.isStartedPlayback,MA_FALSE);
}
Mr Ms;
}
static Me ma_device_stop__wasapi(ma_device*Md)
{
Me Mf;
MA_ASSERT(Md !=NULL);
ma_mutex_lock(&Md->wasapi.rerouteLock);
{
Mf=ma_device_stop__wasapi_nolock(Md);
}
ma_mutex_unlock(&Md->wasapi.rerouteLock);
Mr Mf;
}
#ifndef MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS
#define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000
#endif
static Me ma_device_read__wasapi(ma_device*Md,Mv*pFrames,M3 frameCount,M3*pFramesRead)
{
Me Mf=Ms;
M3 totalFramesProcessed=0;
while (ma_device_get_state(Md)==ma_device_state_started&&totalFramesProcessed<frameCount) {
M3 framesRemaining=frameCount-totalFramesProcessed;
if (Md->wasapi.pMappedBufferCapture !=NULL) {
M3 framesToProcessNow=framesRemaining;
if (framesToProcessNow>Md->wasapi.mappedBufferCaptureLen) {
framesToProcessNow=Md->wasapi.mappedBufferCaptureLen;
}
ma_copy_pcm_frames(
ma_offset_pcm_frames_ptr(pFrames,totalFramesProcessed,Md->capture.internalFormat,Md->capture.internalChannels),ma_offset_pcm_frames_const_ptr(Md->wasapi.pMappedBufferCapture,Md->wasapi.mappedBufferCaptureCap-Md->wasapi.mappedBufferCaptureLen,Md->capture.internalFormat,Md->capture.internalChannels),framesToProcessNow,Md->capture.internalFormat,Md->capture.internalChannels
);
totalFramesProcessed+=framesToProcessNow;
Md->wasapi.mappedBufferCaptureLen-=framesToProcessNow;
if (Md->wasapi.mappedBufferCaptureLen==0) {
ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,Md->wasapi.mappedBufferCaptureCap);
Md->wasapi.pMappedBufferCapture=NULL;
Md->wasapi.mappedBufferCaptureCap=0;
}
} else {
HRESULT hr;
DWORD flags=0;
hr=ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,(BYTE**)&Md->wasapi.pMappedBufferCapture,&Md->wasapi.mappedBufferCaptureCap,&flags,NULL,NULL);
if (hr==S_OK) {
Md->wasapi.mappedBufferCaptureLen=Md->wasapi.mappedBufferCaptureCap;
#if defined(MA_DEBUG_OUTPUT)
{
 if (flags !=0) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags);
 if ((flags&MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) !=0) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=%d\n", Md->wasapi.mappedBufferCaptureCap);
 }
 }
}
#endif
if ((flags&MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) !=0) {
 if (Md->type==ma_device_type_duplex) {
 M3 i;
 M3 periodCount=(Md->wasapi.actualBufferSizeInFramesCapture / Md->wasapi.periodSizeInFramesCapture);
 M3 iterationCount=periodCount / 2;
 if ((periodCount % 2)>0) {
 iterationCount+=1;
 }
 for (i=0; i<iterationCount; i+=1) {
 hr=ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,Md->wasapi.mappedBufferCaptureCap);
 if (FAILED(hr)) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_ReleaseBuffer() failed with %ld.\n", hr);
 break;
 }
 flags=0;
 hr=ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,(BYTE**)&Md->wasapi.pMappedBufferCapture,&Md->wasapi.mappedBufferCaptureCap,&flags,NULL,NULL);
 if (hr==MA_AUDCLNT_S_BUFFER_EMPTY||FAILED(hr)) {
 Md->wasapi.pMappedBufferCapture=NULL;
 Md->wasapi.mappedBufferCaptureCap=0;
 Md->wasapi.mappedBufferCaptureLen=0;
 if (hr==MA_AUDCLNT_S_BUFFER_EMPTY) {
 if ((flags&MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) !=0) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied, and data discontinuity still reported.\n");
 } else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied.\n");
 }
 }
 if (FAILED(hr)) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_GetBuffer() failed with %ld.\n", hr);
 }
 break;
 }
 }
 if (Md->wasapi.pMappedBufferCapture !=NULL) {
 Md->wasapi.mappedBufferCaptureLen=Md->wasapi.mappedBufferCaptureCap;
 }
 }
}
continue;
} else {
if (hr==MA_AUDCLNT_S_BUFFER_EMPTY||hr==MA_AUDCLNT_E_BUFFER_ERROR) {
 DWORD timeoutInMilliseconds=MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS;
 if (Md->type==ma_device_type_loopback) {
 timeoutInMilliseconds=10;
 }
 if (WaitForSingleObject((HANDLE)Md->wasapi.hEventCapture,timeoutInMilliseconds) !=WAIT_OBJECT_0) {
 if (Md->type==ma_device_type_loopback) {
 continue;
 } else {
 Mf=MA_ERROR;
 break;
 }
 }
} else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for reading from the device. HRESULT = %d. Stopping device.\n", (int)hr);
 Mf=ma_result_from_HRESULT(hr);
 break;
}
}
}
}
if (totalFramesProcessed<frameCount&&Md->wasapi.pMappedBufferCapture !=NULL) {
ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)Md->wasapi.pCaptureClient,Md->wasapi.mappedBufferCaptureCap);
Md->wasapi.pMappedBufferCapture=NULL;
Md->wasapi.mappedBufferCaptureCap=0;
Md->wasapi.mappedBufferCaptureLen=0;
}
if (pFramesRead !=NULL) {
*pFramesRead=totalFramesProcessed;
}
Mr Mf;
}
static Me ma_device_write__wasapi(ma_device*Md,const Mv*pFrames,M3 frameCount,M3*pFramesWritten)
{
Me Mf=Ms;
M3 totalFramesProcessed=0;
while (ma_device_get_state(Md)==ma_device_state_started&&totalFramesProcessed<frameCount) {
M3 framesRemaining=frameCount-totalFramesProcessed;
if (Md->wasapi.pMappedBufferPlayback !=NULL) {
M3 framesToProcessNow=framesRemaining;
if (framesToProcessNow>(Md->wasapi.mappedBufferPlaybackCap-Md->wasapi.mappedBufferPlaybackLen)) {
framesToProcessNow=(Md->wasapi.mappedBufferPlaybackCap-Md->wasapi.mappedBufferPlaybackLen);
}
ma_copy_pcm_frames(
ma_offset_pcm_frames_ptr(Md->wasapi.pMappedBufferPlayback,Md->wasapi.mappedBufferPlaybackLen,Md->playback.internalFormat,Md->playback.internalChannels),ma_offset_pcm_frames_const_ptr(pFrames,totalFramesProcessed,Md->playback.internalFormat,Md->playback.internalChannels),framesToProcessNow,Md->playback.internalFormat,Md->playback.internalChannels
);
totalFramesProcessed+=framesToProcessNow;
Md->wasapi.mappedBufferPlaybackLen+=framesToProcessNow;
if (Md->wasapi.mappedBufferPlaybackLen==Md->wasapi.mappedBufferPlaybackCap) {
ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)Md->wasapi.pRenderClient,Md->wasapi.mappedBufferPlaybackCap,0);
Md->wasapi.pMappedBufferPlayback=NULL;
Md->wasapi.mappedBufferPlaybackCap=0;
Md->wasapi.mappedBufferPlaybackLen=0;
if (Md->playback.shareMode==ma_share_mode_exclusive) {
 if (WaitForSingleObject((HANDLE)Md->wasapi.hEventPlayback,MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) !=WAIT_OBJECT_0) {
 Mf=MA_ERROR;
 break;
 }
}
}
} else {
HRESULT hr;
M3 bufferSizeInFrames;
if (Md->playback.shareMode==ma_share_mode_exclusive) {
bufferSizeInFrames=Md->wasapi.actualBufferSizeInFramesPlayback;
} else {
bufferSizeInFrames=Md->wasapi.periodSizeInFramesPlayback;
}
hr=ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)Md->wasapi.pRenderClient,bufferSizeInFrames,(BYTE**)&Md->wasapi.pMappedBufferPlayback);
if (hr==S_OK) {
Md->wasapi.mappedBufferPlaybackCap=bufferSizeInFrames;
Md->wasapi.mappedBufferPlaybackLen=0;
} else {
if (hr==MA_AUDCLNT_E_BUFFER_TOO_LARGE||hr==MA_AUDCLNT_E_BUFFER_ERROR) {
 if (WaitForSingleObject((HANDLE)Md->wasapi.hEventPlayback,MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) !=WAIT_OBJECT_0) {
 Mf=MA_ERROR;
 break;
 }
} else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device. HRESULT = %d. Stopping device.\n", (int)hr);
 Mf=ma_result_from_HRESULT(hr);
 break;
}
}
}
}
if (pFramesWritten !=NULL) {
*pFramesWritten=totalFramesProcessed;
}
Mr Mf;
}
static Me ma_device_data_loop_wakeup__wasapi(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex||Md->type==ma_device_type_loopback) {
SetEvent((HANDLE)Md->wasapi.hEventCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
SetEvent((HANDLE)Md->wasapi.hEventPlayback);
}
Mr Ms;
}
static Me ma_context_uninit__wasapi(ma_context*Mc)
{
ma_context_command__wasapi cmd=ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI);
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_wasapi);
ma_context_post_command__wasapi(Mc,&cmd);
ma_thread_wait(&Mc->wasapi.commandThread);
if (Mc->wasapi.hAvrt) {
ma_dlclose(ma_context_get_log(Mc),Mc->wasapi.hAvrt);
Mc->wasapi.hAvrt=NULL;
}
#if defined(MA_WIN32_UWP)
{
if (Mc->wasapi.hMMDevapi) {
ma_dlclose(ma_context_get_log(Mc),Mc->wasapi.hMMDevapi);
Mc->wasapi.hMMDevapi=NULL;
}
}
#endif
ma_semaphore_uninit(&Mc->wasapi.commandSem);
ma_mutex_uninit(&Mc->wasapi.commandLock);
Mr Ms;
}
static Me ma_context_init__wasapi(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
Me Mf=Ms;
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
#ifdef MA_WIN32_DESKTOP
{
ma_OSVERSIONINFOEXW osvi;
ma_handle kernel32DLL;
ma_PFNVerifyVersionInfoW _VerifyVersionInfoW;
ma_PFNVerSetConditionMask _VerSetConditionMask;
kernel32DLL = ma_dlopen(ma_context_get_log(Mc), "kernel32.dll");
if (kernel32DLL==NULL) {
Mr MA_NO_BACKEND;
}
_VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW )ma_dlsym(ma_context_get_log(Mc), kernel32DLL, "VerifyVersionInfoW");
_VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(ma_context_get_log(Mc), kernel32DLL, "VerSetConditionMask");
if (_VerifyVersionInfoW==NULL||_VerSetConditionMask==NULL) {
ma_dlclose(ma_context_get_log(Mc),kernel32DLL);
Mr MA_NO_BACKEND;
}
MA_ZERO_OBJECT(&osvi);
osvi.dwOSVersionInfoSize=sizeof(osvi);
osvi.dwMajorVersion=((MA_WIN32_WINNT_VISTA>>8)&0xFF);
osvi.dwMinorVersion=((MA_WIN32_WINNT_VISTA>>0)&0xFF);
osvi.wServicePackMajor=1;
if (_VerifyVersionInfoW(&osvi,MA_VER_MAJORVERSION|MA_VER_MINORVERSION|MA_VER_SERVICEPACKMAJOR,_VerSetConditionMask(_VerSetConditionMask(_VerSetConditionMask(0,MA_VER_MAJORVERSION,MA_VER_GREATER_EQUAL),MA_VER_MINORVERSION,MA_VER_GREATER_EQUAL),MA_VER_SERVICEPACKMAJOR,MA_VER_GREATER_EQUAL))) {
Mf=Ms;
} else {
Mf=MA_NO_BACKEND;
}
ma_dlclose(ma_context_get_log(Mc),kernel32DLL);
}
#endif
if (Mf !=Ms) {
Mr Mf;
}
MA_ZERO_OBJECT(&Mc->wasapi);
#if defined(MA_WIN32_UWP)
{
Mc->wasapi.hMMDevapi = ma_dlopen(ma_context_get_log(Mc), "mmdevapi.dll");
if (Mc->wasapi.hMMDevapi) {
Mc->wasapi.ActivateAudioInterfaceAsync = ma_dlsym(ma_context_get_log(Mc), Mc->wasapi.hMMDevapi, "ActivateAudioInterfaceAsync");
if (Mc->wasapi.ActivateAudioInterfaceAsync==NULL) {
ma_dlclose(ma_context_get_log(Mc),Mc->wasapi.hMMDevapi);
Mr MA_NO_BACKEND;
}
} else {
Mr MA_NO_BACKEND;
}
}
#endif
Mc->wasapi.hAvrt = ma_dlopen(ma_context_get_log(Mc), "avrt.dll");
if (Mc->wasapi.hAvrt) {
Mc->wasapi.AvSetMmThreadCharacteristicsA = ma_dlsym(ma_context_get_log(Mc), Mc->wasapi.hAvrt, "AvSetMmThreadCharacteristicsA");
Mc->wasapi.AvRevertMmThreadcharacteristics = ma_dlsym(ma_context_get_log(Mc), Mc->wasapi.hAvrt, "AvRevertMmThreadCharacteristics");
if (!Mc->wasapi.AvSetMmThreadCharacteristicsA||!Mc->wasapi.AvRevertMmThreadcharacteristics) {
Mc->wasapi.AvSetMmThreadCharacteristicsA=NULL;
Mc->wasapi.AvRevertMmThreadcharacteristics=NULL;
ma_dlclose(ma_context_get_log(Mc),Mc->wasapi.hAvrt);
Mc->wasapi.hAvrt=NULL;
}
}
{
Mf=ma_mutex_init(&Mc->wasapi.commandLock);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_semaphore_init(0,&Mc->wasapi.commandSem);
if (Mf !=Ms) {
ma_mutex_uninit(&Mc->wasapi.commandLock);
Mr Mf;
}
Mf=ma_thread_create(&Mc->wasapi.commandThread,ma_thread_priority_normal,0,ma_context_command_thread__wasapi,Mc,&Mc->allocationCallbacks);
if (Mf !=Ms) {
ma_semaphore_uninit(&Mc->wasapi.commandSem);
ma_mutex_uninit(&Mc->wasapi.commandLock);
Mr Mf;
}
}
pCallbacks->onContextInit=ma_context_init__wasapi;
pCallbacks->onContextUninit=ma_context_uninit__wasapi;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__wasapi;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__wasapi;
pCallbacks->onDeviceInit=ma_device_init__wasapi;
pCallbacks->onDeviceUninit=ma_device_uninit__wasapi;
pCallbacks->onDeviceStart=ma_device_start__wasapi;
pCallbacks->onDeviceStop=ma_device_stop__wasapi;
pCallbacks->onDeviceRead=ma_device_read__wasapi;
pCallbacks->onDeviceWrite=ma_device_write__wasapi;
pCallbacks->onDeviceDataLoop=NULL;
pCallbacks->onDeviceDataLoopWakeup=ma_device_data_loop_wakeup__wasapi;
Mr Ms;
}
#endif
#ifdef MA_HAS_DSOUND
#define MA_DSSCL_NORMAL 1
#define MA_DSSCL_PRIORITY 2
#define MA_DSSCL_EXCLUSIVE 3
#define MA_DSSCL_WRITEPRIMARY 4
#define MA_DSCAPS_PRIMARYMONO 0x00000001
#define MA_DSCAPS_PRIMARYSTEREO 0x00000002
#define MA_DSCAPS_PRIMARY8BIT 0x00000004
#define MA_DSCAPS_PRIMARY16BIT 0x00000008
#define MA_DSCAPS_CONTINUOUSRATE 0x00000010
#define MA_DSCAPS_EMULDRIVER 0x00000020
#define MA_DSCAPS_CERTIFIED 0x00000040
#define MA_DSCAPS_SECONDARYMONO 0x00000100
#define MA_DSCAPS_SECONDARYSTEREO 0x00000200
#define MA_DSCAPS_SECONDARY8BIT 0x00000400
#define MA_DSCAPS_SECONDARY16BIT 0x00000800
#define MA_DSBCAPS_PRIMARYBUFFER 0x00000001
#define MA_DSBCAPS_STATIC 0x00000002
#define MA_DSBCAPS_LOCHARDWARE 0x00000004
#define MA_DSBCAPS_LOCSOFTWARE 0x00000008
#define MA_DSBCAPS_CTRL3D 0x00000010
#define MA_DSBCAPS_CTRLFREQUENCY 0x00000020
#define MA_DSBCAPS_CTRLPAN 0x00000040
#define MA_DSBCAPS_CTRLVOLUME 0x00000080
#define MA_DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100
#define MA_DSBCAPS_CTRLFX 0x00000200
#define MA_DSBCAPS_STICKYFOCUS 0x00004000
#define MA_DSBCAPS_GLOBALFOCUS 0x00008000
#define MA_DSBCAPS_GETCURRENTPOSITION2 0x00010000
#define MA_DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000
#define MA_DSBCAPS_LOCDEFER 0x00040000
#define MA_DSBCAPS_TRUEPLAYPOSITION 0x00080000
#define MA_DSBPLAY_LOOPING 0x00000001
#define MA_DSBPLAY_LOCHARDWARE 0x00000002
#define MA_DSBPLAY_LOCSOFTWARE 0x00000004
#define MA_DSBPLAY_TERMINATEBY_TIME 0x00000008
#define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010
#define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020
#define MA_DSBSTATUS_PLAYING 0x00000001
#define MA_DSBSTATUS_BUFFERLOST 0x00000002
#define MA_DSBSTATUS_LOOPING 0x00000004
#define MA_DSBSTATUS_LOCHARDWARE 0x00000008
#define MA_DSBSTATUS_LOCSOFTWARE 0x00000010
#define MA_DSBSTATUS_TERMINATED 0x00000020
#define MA_DSCBSTART_LOOPING 0x00000001
typedef struct
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwBufferBytes;
DWORD dwReserved;
MA_WAVEFORMATEX*lpwfxFormat;
GUID guid3DAlgorithm;
} MA_DSBUFFERDESC;
typedef struct
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwBufferBytes;
DWORD dwReserved;
MA_WAVEFORMATEX*lpwfxFormat;
DWORD dwFXCount;
Mv*lpDSCFXDesc;
} MA_DSCBUFFERDESC;
typedef struct
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwMinSecondarySampleRate;
DWORD dwMaxSecondarySampleRate;
DWORD dwPrimaryBuffers;
DWORD dwMaxHwMixingAllBuffers;
DWORD dwMaxHwMixingStaticBuffers;
DWORD dwMaxHwMixingStreamingBuffers;
DWORD dwFreeHwMixingAllBuffers;
DWORD dwFreeHwMixingStaticBuffers;
DWORD dwFreeHwMixingStreamingBuffers;
DWORD dwMaxHw3DAllBuffers;
DWORD dwMaxHw3DStaticBuffers;
DWORD dwMaxHw3DStreamingBuffers;
DWORD dwFreeHw3DAllBuffers;
DWORD dwFreeHw3DStaticBuffers;
DWORD dwFreeHw3DStreamingBuffers;
DWORD dwTotalHwMemBytes;
DWORD dwFreeHwMemBytes;
DWORD dwMaxContigFreeHwMemBytes;
DWORD dwUnlockTransferRateHwBuffers;
DWORD dwPlayCpuOverheadSwBuffers;
DWORD dwReserved1;
DWORD dwReserved2;
} MA_DSCAPS;
typedef struct
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwBufferBytes;
DWORD dwUnlockTransferRate;
DWORD dwPlayCpuOverhead;
} MA_DSBCAPS;
typedef struct
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwFormats;
DWORD dwChannels;
} MA_DSCCAPS;
typedef struct
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwBufferBytes;
DWORD dwReserved;
} MA_DSCBCAPS;
typedef struct
{
DWORD dwOffset;
HANDLE hEventNotify;
} MA_DSBPOSITIONNOTIFY;
typedef struct ma_IDirectSound ma_IDirectSound;
typedef struct ma_IDirectSoundBuffer ma_IDirectSoundBuffer;
typedef struct ma_IDirectSoundCapture ma_IDirectSoundCapture;
typedef struct ma_IDirectSoundCaptureBuffer ma_IDirectSoundCaptureBuffer;
typedef struct ma_IDirectSoundNotify ma_IDirectSoundNotify;
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IDirectSound*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IDirectSound*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IDirectSound*pThis);
HRESULT (STDMETHODCALLTYPE*CreateSoundBuffer) (ma_IDirectSound*pThis,const MA_DSBUFFERDESC*pDSBufferDesc,ma_IDirectSoundBuffer**ppDSBuffer,Mv*pUnkOuter);
HRESULT (STDMETHODCALLTYPE*GetCaps) (ma_IDirectSound*pThis,MA_DSCAPS*pDSCaps);
HRESULT (STDMETHODCALLTYPE*DuplicateSoundBuffer)(ma_IDirectSound*pThis,ma_IDirectSoundBuffer*pDSBufferOriginal,ma_IDirectSoundBuffer**ppDSBufferDuplicate);
HRESULT (STDMETHODCALLTYPE*SetCooperativeLevel) (ma_IDirectSound*pThis,HWND hwnd,DWORD dwLevel);
HRESULT (STDMETHODCALLTYPE*Compact) (ma_IDirectSound*pThis);
HRESULT (STDMETHODCALLTYPE*GetSpeakerConfig) (ma_IDirectSound*pThis,DWORD*pSpeakerConfig);
HRESULT (STDMETHODCALLTYPE*SetSpeakerConfig) (ma_IDirectSound*pThis,DWORD dwSpeakerConfig);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IDirectSound*pThis,const GUID*pGuidDevice);
} ma_IDirectSoundVtbl;
struct ma_IDirectSound
{
ma_IDirectSoundVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IDirectSound_QueryInterface(ma_IDirectSound*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IDirectSound_AddRef(ma_IDirectSound*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IDirectSound_Release(ma_IDirectSound*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IDirectSound_CreateSoundBuffer(ma_IDirectSound*pThis,const MA_DSBUFFERDESC*pDSBufferDesc,ma_IDirectSoundBuffer**ppDSBuffer,Mv*pUnkOuter) { Mr pThis->lpVtbl->CreateSoundBuffer(pThis,pDSBufferDesc,ppDSBuffer,pUnkOuter); }
static MA_INLINE HRESULT ma_IDirectSound_GetCaps(ma_IDirectSound*pThis,MA_DSCAPS*pDSCaps) { Mr pThis->lpVtbl->GetCaps(pThis,pDSCaps); }
static MA_INLINE HRESULT ma_IDirectSound_DuplicateSoundBuffer(ma_IDirectSound*pThis,ma_IDirectSoundBuffer*pDSBufferOriginal,ma_IDirectSoundBuffer**ppDSBufferDuplicate) { Mr pThis->lpVtbl->DuplicateSoundBuffer(pThis,pDSBufferOriginal,ppDSBufferDuplicate); }
static MA_INLINE HRESULT ma_IDirectSound_SetCooperativeLevel(ma_IDirectSound*pThis,HWND hwnd,DWORD dwLevel) { Mr pThis->lpVtbl->SetCooperativeLevel(pThis,hwnd,dwLevel); }
static MA_INLINE HRESULT ma_IDirectSound_Compact(ma_IDirectSound*pThis) { Mr pThis->lpVtbl->Compact(pThis); }
static MA_INLINE HRESULT ma_IDirectSound_GetSpeakerConfig(ma_IDirectSound*pThis,DWORD*pSpeakerConfig) { Mr pThis->lpVtbl->GetSpeakerConfig(pThis,pSpeakerConfig); }
static MA_INLINE HRESULT ma_IDirectSound_SetSpeakerConfig(ma_IDirectSound*pThis,DWORD dwSpeakerConfig) { Mr pThis->lpVtbl->SetSpeakerConfig(pThis,dwSpeakerConfig); }
static MA_INLINE HRESULT ma_IDirectSound_Initialize(ma_IDirectSound*pThis,const GUID*pGuidDevice) { Mr pThis->lpVtbl->Initialize(pThis,pGuidDevice); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IDirectSoundBuffer*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IDirectSoundBuffer*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IDirectSoundBuffer*pThis);
HRESULT (STDMETHODCALLTYPE*GetCaps) (ma_IDirectSoundBuffer*pThis,MA_DSBCAPS*pDSBufferCaps);
HRESULT (STDMETHODCALLTYPE*GetCurrentPosition)(ma_IDirectSoundBuffer*pThis,DWORD*pCurrentPlayCursor,DWORD*pCurrentWriteCursor);
HRESULT (STDMETHODCALLTYPE*GetFormat) (ma_IDirectSoundBuffer*pThis,MA_WAVEFORMATEX*pFormat,DWORD dwSizeAllocated,DWORD*pSizeWritten);
HRESULT (STDMETHODCALLTYPE*GetVolume) (ma_IDirectSoundBuffer*pThis,LONG*pVolume);
HRESULT (STDMETHODCALLTYPE*GetPan) (ma_IDirectSoundBuffer*pThis,LONG*pPan);
HRESULT (STDMETHODCALLTYPE*GetFrequency) (ma_IDirectSoundBuffer*pThis,DWORD*pFrequency);
HRESULT (STDMETHODCALLTYPE*GetStatus) (ma_IDirectSoundBuffer*pThis,DWORD*pStatus);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IDirectSoundBuffer*pThis,ma_IDirectSound*pDirectSound,const MA_DSBUFFERDESC*pDSBufferDesc);
HRESULT (STDMETHODCALLTYPE*Lock) (ma_IDirectSoundBuffer*pThis,DWORD dwOffset,DWORD dwBytes,Mv**ppAudioPtr1,DWORD*pAudioBytes1,Mv**ppAudioPtr2,DWORD*pAudioBytes2,DWORD dwFlags);
HRESULT (STDMETHODCALLTYPE*Play) (ma_IDirectSoundBuffer*pThis,DWORD dwReserved1,DWORD dwPriority,DWORD dwFlags);
HRESULT (STDMETHODCALLTYPE*SetCurrentPosition)(ma_IDirectSoundBuffer*pThis,DWORD dwNewPosition);
HRESULT (STDMETHODCALLTYPE*SetFormat) (ma_IDirectSoundBuffer*pThis,const MA_WAVEFORMATEX*pFormat);
HRESULT (STDMETHODCALLTYPE*SetVolume) (ma_IDirectSoundBuffer*pThis,LONG volume);
HRESULT (STDMETHODCALLTYPE*SetPan) (ma_IDirectSoundBuffer*pThis,LONG pan);
HRESULT (STDMETHODCALLTYPE*SetFrequency) (ma_IDirectSoundBuffer*pThis,DWORD dwFrequency);
HRESULT (STDMETHODCALLTYPE*Stop) (ma_IDirectSoundBuffer*pThis);
HRESULT (STDMETHODCALLTYPE*Unlock) (ma_IDirectSoundBuffer*pThis,Mv*pAudioPtr1,DWORD dwAudioBytes1,Mv*pAudioPtr2,DWORD dwAudioBytes2);
HRESULT (STDMETHODCALLTYPE*Restore) (ma_IDirectSoundBuffer*pThis);
} ma_IDirectSoundBufferVtbl;
struct ma_IDirectSoundBuffer
{
ma_IDirectSoundBufferVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IDirectSoundBuffer_QueryInterface(ma_IDirectSoundBuffer*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IDirectSoundBuffer_Release(ma_IDirectSoundBuffer*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCaps(ma_IDirectSoundBuffer*pThis,MA_DSBCAPS*pDSBufferCaps) { Mr pThis->lpVtbl->GetCaps(pThis,pDSBufferCaps); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCurrentPosition(ma_IDirectSoundBuffer*pThis,DWORD*pCurrentPlayCursor,DWORD*pCurrentWriteCursor) { Mr pThis->lpVtbl->GetCurrentPosition(pThis,pCurrentPlayCursor,pCurrentWriteCursor); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer*pThis,MA_WAVEFORMATEX*pFormat,DWORD dwSizeAllocated,DWORD*pSizeWritten) { Mr pThis->lpVtbl->GetFormat(pThis,pFormat,dwSizeAllocated,pSizeWritten); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetVolume(ma_IDirectSoundBuffer*pThis,LONG*pVolume) { Mr pThis->lpVtbl->GetVolume(pThis,pVolume); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetPan(ma_IDirectSoundBuffer*pThis,LONG*pPan) { Mr pThis->lpVtbl->GetPan(pThis,pPan); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFrequency(ma_IDirectSoundBuffer*pThis,DWORD*pFrequency) { Mr pThis->lpVtbl->GetFrequency(pThis,pFrequency); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetStatus(ma_IDirectSoundBuffer*pThis,DWORD*pStatus) { Mr pThis->lpVtbl->GetStatus(pThis,pStatus); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer*pThis,ma_IDirectSound*pDirectSound,const MA_DSBUFFERDESC*pDSBufferDesc) { Mr pThis->lpVtbl->Initialize(pThis,pDirectSound,pDSBufferDesc); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_Lock(ma_IDirectSoundBuffer*pThis,DWORD dwOffset,DWORD dwBytes,Mv**ppAudioPtr1,DWORD*pAudioBytes1,Mv**ppAudioPtr2,DWORD*pAudioBytes2,DWORD dwFlags) { Mr pThis->lpVtbl->Lock(pThis,dwOffset,dwBytes,ppAudioPtr1,pAudioBytes1,ppAudioPtr2,pAudioBytes2,dwFlags); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_Play(ma_IDirectSoundBuffer*pThis,DWORD dwReserved1,DWORD dwPriority,DWORD dwFlags) { Mr pThis->lpVtbl->Play(pThis,dwReserved1,dwPriority,dwFlags); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetCurrentPosition(ma_IDirectSoundBuffer*pThis,DWORD dwNewPosition) { Mr pThis->lpVtbl->SetCurrentPosition(pThis,dwNewPosition); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer*pThis,const MA_WAVEFORMATEX*pFormat) { Mr pThis->lpVtbl->SetFormat(pThis,pFormat); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetVolume(ma_IDirectSoundBuffer*pThis,LONG volume) { Mr pThis->lpVtbl->SetVolume(pThis,volume); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetPan(ma_IDirectSoundBuffer*pThis,LONG pan) { Mr pThis->lpVtbl->SetPan(pThis,pan); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFrequency(ma_IDirectSoundBuffer*pThis,DWORD dwFrequency) { Mr pThis->lpVtbl->SetFrequency(pThis,dwFrequency); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_Stop(ma_IDirectSoundBuffer*pThis) { Mr pThis->lpVtbl->Stop(pThis); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_Unlock(ma_IDirectSoundBuffer*pThis,Mv*pAudioPtr1,DWORD dwAudioBytes1,Mv*pAudioPtr2,DWORD dwAudioBytes2) { Mr pThis->lpVtbl->Unlock(pThis,pAudioPtr1,dwAudioBytes1,pAudioPtr2,dwAudioBytes2); }
static MA_INLINE HRESULT ma_IDirectSoundBuffer_Restore(ma_IDirectSoundBuffer*pThis) { Mr pThis->lpVtbl->Restore(pThis); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IDirectSoundCapture*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IDirectSoundCapture*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IDirectSoundCapture*pThis);
HRESULT (STDMETHODCALLTYPE*CreateCaptureBuffer)(ma_IDirectSoundCapture*pThis,const MA_DSCBUFFERDESC*pDSCBufferDesc,ma_IDirectSoundCaptureBuffer**ppDSCBuffer,Mv*pUnkOuter);
HRESULT (STDMETHODCALLTYPE*GetCaps) (ma_IDirectSoundCapture*pThis,MA_DSCCAPS*pDSCCaps);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IDirectSoundCapture*pThis,const GUID*pGuidDevice);
} ma_IDirectSoundCaptureVtbl;
struct ma_IDirectSoundCapture
{
ma_IDirectSoundCaptureVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface (ma_IDirectSoundCapture*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IDirectSoundCapture_AddRef (ma_IDirectSoundCapture*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IDirectSoundCapture_Release (ma_IDirectSoundCapture*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IDirectSoundCapture_CreateCaptureBuffer(ma_IDirectSoundCapture*pThis,const MA_DSCBUFFERDESC*pDSCBufferDesc,ma_IDirectSoundCaptureBuffer**ppDSCBuffer,Mv*pUnkOuter) { Mr pThis->lpVtbl->CreateCaptureBuffer(pThis,pDSCBufferDesc,ppDSCBuffer,pUnkOuter); }
static MA_INLINE HRESULT ma_IDirectSoundCapture_GetCaps (ma_IDirectSoundCapture*pThis,MA_DSCCAPS*pDSCCaps) { Mr pThis->lpVtbl->GetCaps(pThis,pDSCCaps); }
static MA_INLINE HRESULT ma_IDirectSoundCapture_Initialize (ma_IDirectSoundCapture*pThis,const GUID*pGuidDevice) { Mr pThis->lpVtbl->Initialize(pThis,pGuidDevice); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IDirectSoundCaptureBuffer*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IDirectSoundCaptureBuffer*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IDirectSoundCaptureBuffer*pThis);
HRESULT (STDMETHODCALLTYPE*GetCaps) (ma_IDirectSoundCaptureBuffer*pThis,MA_DSCBCAPS*pDSCBCaps);
HRESULT (STDMETHODCALLTYPE*GetCurrentPosition)(ma_IDirectSoundCaptureBuffer*pThis,DWORD*pCapturePosition,DWORD*pReadPosition);
HRESULT (STDMETHODCALLTYPE*GetFormat) (ma_IDirectSoundCaptureBuffer*pThis,MA_WAVEFORMATEX*pFormat,DWORD dwSizeAllocated,DWORD*pSizeWritten);
HRESULT (STDMETHODCALLTYPE*GetStatus) (ma_IDirectSoundCaptureBuffer*pThis,DWORD*pStatus);
HRESULT (STDMETHODCALLTYPE*Initialize) (ma_IDirectSoundCaptureBuffer*pThis,ma_IDirectSoundCapture*pDirectSoundCapture,const MA_DSCBUFFERDESC*pDSCBufferDesc);
HRESULT (STDMETHODCALLTYPE*Lock) (ma_IDirectSoundCaptureBuffer*pThis,DWORD dwOffset,DWORD dwBytes,Mv**ppAudioPtr1,DWORD*pAudioBytes1,Mv**ppAudioPtr2,DWORD*pAudioBytes2,DWORD dwFlags);
HRESULT (STDMETHODCALLTYPE*Start) (ma_IDirectSoundCaptureBuffer*pThis,DWORD dwFlags);
HRESULT (STDMETHODCALLTYPE*Stop) (ma_IDirectSoundCaptureBuffer*pThis);
HRESULT (STDMETHODCALLTYPE*Unlock) (ma_IDirectSoundCaptureBuffer*pThis,Mv*pAudioPtr1,DWORD dwAudioBytes1,Mv*pAudioPtr2,DWORD dwAudioBytes2);
} ma_IDirectSoundCaptureBufferVtbl;
struct ma_IDirectSoundCaptureBuffer
{
ma_IDirectSoundCaptureBufferVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_QueryInterface(ma_IDirectSoundCaptureBuffer*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCaptureBuffer*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_Release(ma_IDirectSoundCaptureBuffer*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCaps(ma_IDirectSoundCaptureBuffer*pThis,MA_DSCBCAPS*pDSCBCaps) { Mr pThis->lpVtbl->GetCaps(pThis,pDSCBCaps); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCurrentPosition(ma_IDirectSoundCaptureBuffer*pThis,DWORD*pCapturePosition,DWORD*pReadPosition) { Mr pThis->lpVtbl->GetCurrentPosition(pThis,pCapturePosition,pReadPosition); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer*pThis,MA_WAVEFORMATEX*pFormat,DWORD dwSizeAllocated,DWORD*pSizeWritten) { Mr pThis->lpVtbl->GetFormat(pThis,pFormat,dwSizeAllocated,pSizeWritten); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetStatus(ma_IDirectSoundCaptureBuffer*pThis,DWORD*pStatus) { Mr pThis->lpVtbl->GetStatus(pThis,pStatus); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Initialize(ma_IDirectSoundCaptureBuffer*pThis,ma_IDirectSoundCapture*pDirectSoundCapture,const MA_DSCBUFFERDESC*pDSCBufferDesc) { Mr pThis->lpVtbl->Initialize(pThis,pDirectSoundCapture,pDSCBufferDesc); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Lock(ma_IDirectSoundCaptureBuffer*pThis,DWORD dwOffset,DWORD dwBytes,Mv**ppAudioPtr1,DWORD*pAudioBytes1,Mv**ppAudioPtr2,DWORD*pAudioBytes2,DWORD dwFlags) { Mr pThis->lpVtbl->Lock(pThis,dwOffset,dwBytes,ppAudioPtr1,pAudioBytes1,ppAudioPtr2,pAudioBytes2,dwFlags); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Start(ma_IDirectSoundCaptureBuffer*pThis,DWORD dwFlags) { Mr pThis->lpVtbl->Start(pThis,dwFlags); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Stop(ma_IDirectSoundCaptureBuffer*pThis) { Mr pThis->lpVtbl->Stop(pThis); }
static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Unlock(ma_IDirectSoundCaptureBuffer*pThis,Mv*pAudioPtr1,DWORD dwAudioBytes1,Mv*pAudioPtr2,DWORD dwAudioBytes2) { Mr pThis->lpVtbl->Unlock(pThis,pAudioPtr1,dwAudioBytes1,pAudioPtr2,dwAudioBytes2); }
typedef struct
{
HRESULT (STDMETHODCALLTYPE*QueryInterface)(ma_IDirectSoundNotify*pThis,const IID*const riid,Mv**ppObject);
ULONG (STDMETHODCALLTYPE*AddRef) (ma_IDirectSoundNotify*pThis);
ULONG (STDMETHODCALLTYPE*Release) (ma_IDirectSoundNotify*pThis);
HRESULT (STDMETHODCALLTYPE*SetNotificationPositions)(ma_IDirectSoundNotify*pThis,DWORD dwPositionNotifies,const MA_DSBPOSITIONNOTIFY*pPositionNotifies);
} ma_IDirectSoundNotifyVtbl;
struct ma_IDirectSoundNotify
{
ma_IDirectSoundNotifyVtbl*lpVtbl;
};
static MA_INLINE HRESULT ma_IDirectSoundNotify_QueryInterface(ma_IDirectSoundNotify*pThis,const IID*const riid,Mv**ppObject) { Mr pThis->lpVtbl->QueryInterface(pThis,riid,ppObject); }
static MA_INLINE ULONG ma_IDirectSoundNotify_AddRef(ma_IDirectSoundNotify*pThis) { Mr pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify*pThis) { Mr pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IDirectSoundNotify_SetNotificationPositions(ma_IDirectSoundNotify*pThis,DWORD dwPositionNotifies,const MA_DSBPOSITIONNOTIFY*pPositionNotifies) { Mr pThis->lpVtbl->SetNotificationPositions(pThis,dwPositionNotifies,pPositionNotifies); }
typedef BOOL (CALLBACK*ma_DSEnumCallbackAProc) (GUID*pDeviceGUID,const char*pDeviceDescription,const char*pModule,Mv*Mc);
typedef HRESULT (WINAPI*ma_DirectSoundCreateProc) (const GUID*pcGuidDevice,ma_IDirectSound**ppDS8,ma_IUnknown*pUnkOuter);
typedef HRESULT (WINAPI*ma_DirectSoundEnumerateAProc) (ma_DSEnumCallbackAProc pDSEnumCallback,Mv*Mc);
typedef HRESULT (WINAPI*ma_DirectSoundCaptureCreateProc) (const GUID*pcGuidDevice,ma_IDirectSoundCapture**ppDSC8,ma_IUnknown*pUnkOuter);
typedef HRESULT (WINAPI*ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback,Mv*Mc);
static M3 ma_get_best_sample_rate_within_range(M3 sampleRateMin,M3 sampleRateMax)
{
if (sampleRateMin<(M3)ma_standard_sample_rate_min) {
sampleRateMin=(M3)ma_standard_sample_rate_min;
}
if (sampleRateMax>(M3)ma_standard_sample_rate_max) {
sampleRateMax=(M3)ma_standard_sample_rate_max;
}
if (sampleRateMin>sampleRateMax) {
sampleRateMin=sampleRateMax;
}
if (sampleRateMin==sampleRateMax) {
Mr sampleRateMax;
} else {
size_t iStandardRate;
for (iStandardRate=0; iStandardRate<ma_countof(g_maStandardSampleRatePriorities);++iStandardRate) {
M3 standardRate=g_maStandardSampleRatePriorities[iStandardRate];
if (standardRate>=sampleRateMin&&standardRate<=sampleRateMax) {
Mr standardRate;
}
}
}
MA_ASSERT(MA_FALSE);
Mr 0;
}
static Mv ma_get_channels_from_speaker_config__dsound(DWORD speakerConfig,WORD*pChannelsOut,DWORD*pChannelMapOut)
{
WORD Mh;
DWORD channelMap;
Mh=0;
if (pChannelsOut !=NULL) {
Mh=*pChannelsOut;
}
channelMap=0;
if (pChannelMapOut !=NULL) {
channelMap=*pChannelMapOut;
}
switch ((BYTE)(speakerConfig)) {
case 1:Mh=2; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT; break;
case 2:Mh=1; channelMap=SPEAKER_FRONT_CENTER; break;
case 3:Mh=4; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT; break;
case 4:Mh=2; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT; break;
case 5:Mh=4; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_BACK_CENTER; break;
case 6:Mh=6; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT; break;
case 7:Mh=8; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER; break;
case 8:Mh=8; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT; break;
case 9:Mh=6; channelMap=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT; break;
default:break;
}
if (pChannelsOut !=NULL) {
*pChannelsOut=Mh;
}
if (pChannelMapOut !=NULL) {
*pChannelMapOut=channelMap;
}
}
static Me ma_context_create_IDirectSound__dsound(ma_context*Mc,ma_share_mode shareMode,const ma_device_id*pDeviceID,ma_IDirectSound**ppDirectSound)
{
ma_IDirectSound*pDirectSound;
HWND hWnd;
HRESULT hr;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppDirectSound !=NULL);
*ppDirectSound=NULL;
pDirectSound=NULL;
if (FAILED(((ma_DirectSoundCreateProc)Mc->dsound.DirectSoundCreate)((pDeviceID==NULL)?NULL:(const GUID*)pDeviceID->dsound,&pDirectSound,NULL))) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
hWnd=(HWND)Mc->dsound.hWnd;
if (hWnd==0) {
hWnd=((MA_PFN_GetForegroundWindow)Mc->win32.GetForegroundWindow)();
if (hWnd==0) {
hWnd=((MA_PFN_GetDesktopWindow)Mc->win32.GetDesktopWindow)();
}
}
hr=ma_IDirectSound_SetCooperativeLevel(pDirectSound,hWnd,(shareMode==ma_share_mode_exclusive)?MA_DSSCL_EXCLUSIVE:MA_DSSCL_PRIORITY);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.");
Mr ma_result_from_HRESULT(hr);
}
*ppDirectSound=pDirectSound;
Mr Ms;
}
static Me ma_context_create_IDirectSoundCapture__dsound(ma_context*Mc,ma_share_mode shareMode,const ma_device_id*pDeviceID,ma_IDirectSoundCapture**ppDirectSoundCapture)
{
ma_IDirectSoundCapture*pDirectSoundCapture;
HRESULT hr;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppDirectSoundCapture !=NULL);
if (shareMode==ma_share_mode_exclusive) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
*ppDirectSoundCapture=NULL;
pDirectSoundCapture=NULL;
hr=((ma_DirectSoundCaptureCreateProc)Mc->dsound.DirectSoundCaptureCreate)((pDeviceID==NULL)?NULL:(const GUID*)pDeviceID->dsound,&pDirectSoundCapture,NULL);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.");
Mr ma_result_from_HRESULT(hr);
}
*ppDirectSoundCapture=pDirectSoundCapture;
Mr Ms;
}
static Me ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_context*Mc,ma_IDirectSoundCapture*pDirectSoundCapture,WORD*pChannels,WORD*pBitsPerSample,DWORD*pSampleRate)
{
HRESULT hr;
MA_DSCCAPS caps;
WORD bitsPerSample;
DWORD sampleRate;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDirectSoundCapture !=NULL);
if (pChannels) {
*pChannels=0;
}
if (pBitsPerSample) {
*pBitsPerSample=0;
}
if (pSampleRate) {
*pSampleRate=0;
}
MA_ZERO_OBJECT(&caps);
caps.dwSize=sizeof(caps);
hr=ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture,&caps);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.");
Mr ma_result_from_HRESULT(hr);
}
if (pChannels) {
*pChannels=(WORD)caps.dwChannels;
}
bitsPerSample=16;
sampleRate=48000;
if (caps.dwChannels==1) {
if ((caps.dwFormats&WAVE_FORMAT_48M16) !=0) {
sampleRate=48000;
} else if ((caps.dwFormats&WAVE_FORMAT_44M16) !=0) {
sampleRate=44100;
} else if ((caps.dwFormats&WAVE_FORMAT_2M16) !=0) {
sampleRate=22050;
} else if ((caps.dwFormats&WAVE_FORMAT_1M16) !=0) {
sampleRate=11025;
} else if ((caps.dwFormats&WAVE_FORMAT_96M16) !=0) {
sampleRate=96000;
} else {
bitsPerSample=8;
if ((caps.dwFormats&WAVE_FORMAT_48M08) !=0) {
sampleRate=48000;
} else if ((caps.dwFormats&WAVE_FORMAT_44M08) !=0) {
sampleRate=44100;
} else if ((caps.dwFormats&WAVE_FORMAT_2M08) !=0) {
sampleRate=22050;
} else if ((caps.dwFormats&WAVE_FORMAT_1M08) !=0) {
sampleRate=11025;
} else if ((caps.dwFormats&WAVE_FORMAT_96M08) !=0) {
sampleRate=96000;
} else {
bitsPerSample=16;
}
}
} else if (caps.dwChannels==2) {
if ((caps.dwFormats&WAVE_FORMAT_48S16) !=0) {
sampleRate=48000;
} else if ((caps.dwFormats&WAVE_FORMAT_44S16) !=0) {
sampleRate=44100;
} else if ((caps.dwFormats&WAVE_FORMAT_2S16) !=0) {
sampleRate=22050;
} else if ((caps.dwFormats&WAVE_FORMAT_1S16) !=0) {
sampleRate=11025;
} else if ((caps.dwFormats&WAVE_FORMAT_96S16) !=0) {
sampleRate=96000;
} else {
bitsPerSample=8;
if ((caps.dwFormats&WAVE_FORMAT_48S08) !=0) {
sampleRate=48000;
} else if ((caps.dwFormats&WAVE_FORMAT_44S08) !=0) {
sampleRate=44100;
} else if ((caps.dwFormats&WAVE_FORMAT_2S08) !=0) {
sampleRate=22050;
} else if ((caps.dwFormats&WAVE_FORMAT_1S08) !=0) {
sampleRate=11025;
} else if ((caps.dwFormats&WAVE_FORMAT_96S08) !=0) {
sampleRate=96000;
} else {
bitsPerSample=16;
}
}
}
if (pBitsPerSample) {
*pBitsPerSample=bitsPerSample;
}
if (pSampleRate) {
*pSampleRate=sampleRate;
}
Mr Ms;
}
typedef struct
{
ma_context*Mc;
ma_device_type deviceType;
ma_enum_devices_callback_proc callback;
Mv*pUserData;
ma_bool32 terminated;
} ma_context_enumerate_devices_callback_data__dsound;
static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(GUID*lpGuid,const char*lpcstrDescription,const char*lpcstrModule,Mv*lpContext)
{
ma_context_enumerate_devices_callback_data__dsound*pData=(ma_context_enumerate_devices_callback_data__dsound*)lpContext;
ma_device_info deviceInfo;
(Mv)lpcstrModule;
MA_ZERO_OBJECT(&deviceInfo);
if (lpGuid !=NULL) {
MA_COPY_MEMORY(deviceInfo.id.dsound,lpGuid,16);
} else {
MA_ZERO_MEMORY(deviceInfo.id.dsound,16);
deviceInfo.isDefault=MA_TRUE;
}
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),lpcstrDescription,(size_t)-1);
MA_ASSERT(pData !=NULL);
pData->terminated=(pData->callback(pData->Mc,pData->deviceType,&deviceInfo,pData->pUserData)==MA_FALSE);
if (pData->terminated) {
Mr FALSE;
} else {
Mr TRUE;
}
}
static Me ma_context_enumerate_devices__dsound(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_context_enumerate_devices_callback_data__dsound data;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
data.Mc=Mc;
data.callback=callback;
data.pUserData=pUserData;
data.terminated=MA_FALSE;
if (!data.terminated) {
data.deviceType=Mt;
((ma_DirectSoundEnumerateAProc)Mc->dsound.DirectSoundEnumerateA)(ma_context_enumerate_devices_callback__dsound,&data);
}
if (!data.terminated) {
data.deviceType=ma_device_type_capture;
((ma_DirectSoundCaptureEnumerateAProc)Mc->dsound.DirectSoundCaptureEnumerateA)(ma_context_enumerate_devices_callback__dsound,&data);
}
Mr Ms;
}
typedef struct
{
const ma_device_id*pDeviceID;
ma_device_info*pDeviceInfo;
ma_bool32 found;
} ma_context_get_device_info_callback_data__dsound;
static BOOL CALLBACK ma_context_get_device_info_callback__dsound(GUID*lpGuid,const char*lpcstrDescription,const char*lpcstrModule,Mv*lpContext)
{
ma_context_get_device_info_callback_data__dsound*pData=(ma_context_get_device_info_callback_data__dsound*)lpContext;
MA_ASSERT(pData !=NULL);
if ((pData->pDeviceID==NULL||ma_is_guid_null(pData->pDeviceID->dsound))&&(lpGuid==NULL||ma_is_guid_null(lpGuid))) {
ma_strncpy_s(pData->pDeviceInfo->name,sizeof(pData->pDeviceInfo->name),lpcstrDescription,(size_t)-1);
pData->pDeviceInfo->isDefault=MA_TRUE;
pData->found=MA_TRUE;
Mr FALSE;
} else {
if (lpGuid !=NULL&&pData->pDeviceID !=NULL) {
if (memcmp(pData->pDeviceID->dsound,lpGuid,sizeof(pData->pDeviceID->dsound))==0) {
ma_strncpy_s(pData->pDeviceInfo->name,sizeof(pData->pDeviceInfo->name),lpcstrDescription,(size_t)-1);
pData->found=MA_TRUE;
Mr FALSE;
}
}
}
(Mv)lpcstrModule;
Mr TRUE;
}
static Me ma_context_get_device_info__dsound(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
Me Mf;
HRESULT hr;
if (pDeviceID !=NULL) {
ma_context_get_device_info_callback_data__dsound data;
MA_COPY_MEMORY(pDeviceInfo->id.dsound,pDeviceID->dsound,16);
data.pDeviceID=pDeviceID;
data.pDeviceInfo=pDeviceInfo;
data.found=MA_FALSE;
if (deviceType==Mt) {
((ma_DirectSoundEnumerateAProc)Mc->dsound.DirectSoundEnumerateA)(ma_context_get_device_info_callback__dsound,&data);
} else {
((ma_DirectSoundCaptureEnumerateAProc)Mc->dsound.DirectSoundCaptureEnumerateA)(ma_context_get_device_info_callback__dsound,&data);
}
if (!data.found) {
Mr MA_NO_DEVICE;
}
} else {
MA_ZERO_MEMORY(pDeviceInfo->id.dsound,16);
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
pDeviceInfo->isDefault=MA_TRUE;
}
if (deviceType==Mt) {
ma_IDirectSound*pDirectSound;
MA_DSCAPS caps;
WORD Mh;
Mf=ma_context_create_IDirectSound__dsound(Mc,ma_share_mode_shared,pDeviceID,&pDirectSound);
if (Mf !=Ms) {
Mr Mf;
}
MA_ZERO_OBJECT(&caps);
caps.dwSize=sizeof(caps);
hr=ma_IDirectSound_GetCaps(pDirectSound,&caps);
if (FAILED(hr)) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.");
Mr ma_result_from_HRESULT(hr);
}
if ((caps.dwFlags&MA_DSCAPS_PRIMARYSTEREO) !=0) {
DWORD speakerConfig;
Mh=2;
hr=ma_IDirectSound_GetSpeakerConfig(pDirectSound,&speakerConfig);
if (SUCCEEDED(hr)) {
ma_get_channels_from_speaker_config__dsound(speakerConfig,&Mh,NULL);
}
} else {
Mh=1;
}
if ((caps.dwFlags&MA_DSCAPS_CONTINUOUSRATE) !=0) {
size_t iStandardSampleRate;
for (iStandardSampleRate=0; iStandardSampleRate<ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate+=1) {
M3 sampleRate=g_maStandardSampleRatePriorities[iStandardSampleRate];
if (sampleRate>=caps.dwMinSecondarySampleRate&&sampleRate<=caps.dwMaxSecondarySampleRate) {
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=ma_format_unknown;
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=Mh;
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=sampleRate;
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=0;
 pDeviceInfo->nativeDataFormatCount+=1;
}
}
} else {
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=ma_format_unknown;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=Mh;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=caps.dwMaxSecondarySampleRate;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=0;
pDeviceInfo->nativeDataFormatCount+=1;
}
ma_IDirectSound_Release(pDirectSound);
} else {
ma_IDirectSoundCapture*pDirectSoundCapture;
WORD Mh;
WORD bitsPerSample;
DWORD sampleRate;
Mf=ma_context_create_IDirectSoundCapture__dsound(Mc,ma_share_mode_shared,pDeviceID,&pDirectSoundCapture);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_context_get_format_info_for_IDirectSoundCapture__dsound(Mc,pDirectSoundCapture,&Mh,&bitsPerSample,&sampleRate);
if (Mf !=Ms) {
ma_IDirectSoundCapture_Release(pDirectSoundCapture);
Mr Mf;
}
ma_IDirectSoundCapture_Release(pDirectSoundCapture);
if (bitsPerSample==8) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_u8;
} else if (bitsPerSample==16) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_s16;
} else if (bitsPerSample==24) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_s24;
} else if (bitsPerSample==32) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_s32;
} else {
Mr MA_FORMAT_NOT_SUPPORTED;
}
pDeviceInfo->nativeDataFormats[0].Mh=Mh;
pDeviceInfo->nativeDataFormats[0].sampleRate=sampleRate;
pDeviceInfo->nativeDataFormats[0].flags=0;
pDeviceInfo->nativeDataFormatCount=1;
}
Mr Ms;
}
static Me ma_device_uninit__dsound(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->dsound.pCaptureBuffer !=NULL) {
ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer);
}
if (Md->dsound.pCapture !=NULL) {
ma_IDirectSoundCapture_Release((ma_IDirectSoundCapture*)Md->dsound.pCapture);
}
if (Md->dsound.pPlaybackBuffer !=NULL) {
ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer);
}
if (Md->dsound.pPlaybackPrimaryBuffer !=NULL) {
ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackPrimaryBuffer);
}
if (Md->dsound.pPlayback !=NULL) {
ma_IDirectSound_Release((ma_IDirectSound*)Md->dsound.pPlayback);
}
Mr Ms;
}
static Me ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format,M3 Mh,M3 sampleRate,const ma_channel*pChannelMap,MA_WAVEFORMATEXTENSIBLE*pWF)
{
GUID subformat;
if (format==ma_format_unknown) {
format=MA_DEFAULT_FORMAT;
}
if (Mh==0) {
Mh=MA_DEFAULT_CHANNELS;
}
if (sampleRate==0) {
sampleRate=MA_DEFAULT_SAMPLE_RATE;
}
switch (format)
{
case ma_format_u8:
case ma_format_s16:
case ma_format_s24:
case ma_format_s32:
{
subformat=MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
} break;
case ma_format_f32:
{
subformat=MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
} break;
default:
Mr MA_FORMAT_NOT_SUPPORTED;
}
MA_ZERO_OBJECT(pWF);
pWF->cbSize=sizeof(*pWF);
pWF->wFormatTag=WAVE_FORMAT_EXTENSIBLE;
pWF->nChannels=(WORD)Mh;
pWF->nSamplesPerSec=(DWORD)sampleRate;
pWF->wBitsPerSample=(WORD)(ma_get_bytes_per_sample(format)*8);
pWF->nBlockAlign=(WORD)(pWF->nChannels*pWF->wBitsPerSample / 8);
pWF->nAvgBytesPerSec=pWF->nBlockAlign*pWF->nSamplesPerSec;
pWF->Samples.wValidBitsPerSample=pWF->wBitsPerSample;
pWF->dwChannelMask=ma_channel_map_to_channel_mask__win32(pChannelMap,Mh);
pWF->SubFormat=subformat;
Mr Ms;
}
static M3 ma_calculate_period_size_in_frames_from_descriptor__dsound(const ma_device_descriptor*pDescriptor,M3 nativeSampleRate,ma_performance_profile performanceProfile)
{
M3 minPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(30,nativeSampleRate);
M3 periodSizeInFrames;
periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,nativeSampleRate,performanceProfile);
if (periodSizeInFrames<minPeriodSizeInFrames) {
periodSizeInFrames=minPeriodSizeInFrames;
}
Mr periodSizeInFrames;
}
static Me ma_device_init__dsound(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
HRESULT hr;
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->dsound);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
MA_WAVEFORMATEXTENSIBLE wf;
MA_DSCBUFFERDESC descDS;
M3 periodSizeInFrames;
M3 periodCount;
char rawdata[1024];
MA_WAVEFORMATEXTENSIBLE*pActualFormat;
Mf=ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorCapture->format,pDescriptorCapture->Mh,pDescriptorCapture->sampleRate,pDescriptorCapture->channelMap,&wf);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_context_create_IDirectSoundCapture__dsound(Md->Mc,pDescriptorCapture->shareMode,pDescriptorCapture->pDeviceID,(ma_IDirectSoundCapture**)&Md->dsound.pCapture);
if (Mf !=Ms) {
ma_device_uninit__dsound(Md);
Mr Mf;
}
Mf=ma_context_get_format_info_for_IDirectSoundCapture__dsound(Md->Mc,(ma_IDirectSoundCapture*)Md->dsound.pCapture,&wf.nChannels,&wf.wBitsPerSample,&wf.nSamplesPerSec);
if (Mf !=Ms) {
ma_device_uninit__dsound(Md);
Mr Mf;
}
wf.nBlockAlign=(WORD)(wf.nChannels*wf.wBitsPerSample / 8);
wf.nAvgBytesPerSec=wf.nBlockAlign*wf.nSamplesPerSec;
wf.Samples.wValidBitsPerSample=wf.wBitsPerSample;
wf.SubFormat=MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorCapture,wf.nSamplesPerSec,Mo->performanceProfile);
periodCount=(pDescriptorCapture->periodCount>0)?pDescriptorCapture->periodCount:MA_DEFAULT_PERIODS;
MA_ZERO_OBJECT(&descDS);
descDS.dwSize=sizeof(descDS);
descDS.dwFlags=0;
descDS.dwBufferBytes=periodSizeInFrames*periodCount*wf.nBlockAlign;
descDS.lpwfxFormat=(MA_WAVEFORMATEX*)&wf;
hr=ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)Md->dsound.pCapture,&descDS,(ma_IDirectSoundCaptureBuffer**)&Md->dsound.pCaptureBuffer,NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.");
Mr ma_result_from_HRESULT(hr);
}
pActualFormat=(MA_WAVEFORMATEXTENSIBLE*)rawdata;
hr=ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,(MA_WAVEFORMATEX*)pActualFormat,sizeof(rawdata),NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.");
Mr ma_result_from_HRESULT(hr);
}
pDescriptorCapture->format=ma_format_from_WAVEFORMATEX((MA_WAVEFORMATEX*)pActualFormat);
pDescriptorCapture->Mh=pActualFormat->nChannels;
pDescriptorCapture->sampleRate=pActualFormat->nSamplesPerSec;
if (pActualFormat->wFormatTag==WAVE_FORMAT_EXTENSIBLE) {
ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask,pDescriptorCapture->Mh,pDescriptorCapture->channelMap);
} else {
ma_channel_mask_to_channel_map__win32(wf.dwChannelMask,pDescriptorCapture->Mh,pDescriptorCapture->channelMap);
}
if (periodSizeInFrames !=(descDS.dwBufferBytes / ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh) / periodCount)) {
descDS.dwBufferBytes=periodSizeInFrames*ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh)*periodCount;
ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer);
hr=ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)Md->dsound.pCapture,&descDS,(ma_IDirectSoundCaptureBuffer**)&Md->dsound.pCaptureBuffer,NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.");
Mr ma_result_from_HRESULT(hr);
}
}
pDescriptorCapture->periodSizeInFrames=periodSizeInFrames;
pDescriptorCapture->periodCount=periodCount;
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
MA_WAVEFORMATEXTENSIBLE wf;
MA_DSBUFFERDESC descDSPrimary;
MA_DSCAPS caps;
char rawdata[1024];
MA_WAVEFORMATEXTENSIBLE*pActualFormat;
M3 periodSizeInFrames;
M3 periodCount;
MA_DSBUFFERDESC descDS;
WORD nativeChannelCount;
DWORD nativeChannelMask=0;
Mf=ma_config_to_WAVEFORMATEXTENSIBLE(Mp->format,Mp->Mh,Mp->sampleRate,Mp->channelMap,&wf);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_context_create_IDirectSound__dsound(Md->Mc,Mp->shareMode,Mp->pDeviceID,(ma_IDirectSound**)&Md->dsound.pPlayback);
if (Mf !=Ms) {
ma_device_uninit__dsound(Md);
Mr Mf;
}
MA_ZERO_OBJECT(&descDSPrimary);
descDSPrimary.dwSize=sizeof(MA_DSBUFFERDESC);
descDSPrimary.dwFlags=MA_DSBCAPS_PRIMARYBUFFER|MA_DSBCAPS_CTRLVOLUME;
hr=ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)Md->dsound.pPlayback,&descDSPrimary,(ma_IDirectSoundBuffer**)&Md->dsound.pPlaybackPrimaryBuffer,NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.");
Mr ma_result_from_HRESULT(hr);
}
MA_ZERO_OBJECT(&caps);
caps.dwSize=sizeof(caps);
hr=ma_IDirectSound_GetCaps((ma_IDirectSound*)Md->dsound.pPlayback,&caps);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.");
Mr ma_result_from_HRESULT(hr);
}
if ((caps.dwFlags&MA_DSCAPS_PRIMARYSTEREO) !=0) {
DWORD speakerConfig;
nativeChannelCount=2;
if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)Md->dsound.pPlayback,&speakerConfig))) {
ma_get_channels_from_speaker_config__dsound(speakerConfig,&nativeChannelCount,&nativeChannelMask);
}
} else {
nativeChannelCount=1;
nativeChannelMask=0x00000001;
}
if (Mp->Mh==0) {
wf.nChannels=nativeChannelCount;
wf.dwChannelMask=nativeChannelMask;
}
if (Mp->sampleRate==0) {
if ((caps.dwFlags&MA_DSCAPS_CONTINUOUSRATE) !=0) {
wf.nSamplesPerSec=ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate,caps.dwMaxSecondarySampleRate);
} else {
wf.nSamplesPerSec=caps.dwMaxSecondarySampleRate;
}
}
wf.nBlockAlign=(WORD)(wf.nChannels*wf.wBitsPerSample / 8);
wf.nAvgBytesPerSec=wf.nBlockAlign*wf.nSamplesPerSec;
hr=ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackPrimaryBuffer,(MA_WAVEFORMATEX*)&wf);
if (FAILED(hr)) {
wf.cbSize=18;
wf.wFormatTag=WAVE_FORMAT_PCM;
wf.wBitsPerSample=16;
wf.nChannels=nativeChannelCount;
wf.nSamplesPerSec=44100;
wf.nBlockAlign=wf.nChannels*(wf.wBitsPerSample / 8);
wf.nAvgBytesPerSec=wf.nSamplesPerSec*wf.nBlockAlign;
hr=ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackPrimaryBuffer,(MA_WAVEFORMATEX*)&wf);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.");
Mr ma_result_from_HRESULT(hr);
}
}
pActualFormat=(MA_WAVEFORMATEXTENSIBLE*)rawdata;
hr=ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackPrimaryBuffer,(MA_WAVEFORMATEX*)pActualFormat,sizeof(rawdata),NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.");
Mr ma_result_from_HRESULT(hr);
}
Mp->format=ma_format_from_WAVEFORMATEX((MA_WAVEFORMATEX*)pActualFormat);
Mp->Mh=pActualFormat->nChannels;
Mp->sampleRate=pActualFormat->nSamplesPerSec;
if (pActualFormat->wFormatTag==WAVE_FORMAT_EXTENSIBLE) {
ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask,Mp->Mh,Mp->channelMap);
} else {
ma_channel_mask_to_channel_map__win32(wf.dwChannelMask,Mp->Mh,Mp->channelMap);
}
periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__dsound(Mp,Mp->sampleRate,Mo->performanceProfile);
periodCount=(Mp->periodCount>0)?Mp->periodCount:MA_DEFAULT_PERIODS;
MA_ZERO_OBJECT(&descDS);
descDS.dwSize=sizeof(descDS);
descDS.dwFlags=MA_DSBCAPS_CTRLPOSITIONNOTIFY|MA_DSBCAPS_GLOBALFOCUS|MA_DSBCAPS_GETCURRENTPOSITION2;
descDS.dwBufferBytes=periodSizeInFrames*periodCount*ma_get_bytes_per_frame(Mp->format,Mp->Mh);
descDS.lpwfxFormat=(MA_WAVEFORMATEX*)pActualFormat;
hr=ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)Md->dsound.pPlayback,&descDS,(ma_IDirectSoundBuffer**)&Md->dsound.pPlaybackBuffer,NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.");
Mr ma_result_from_HRESULT(hr);
}
Mp->periodSizeInFrames=periodSizeInFrames;
Mp->periodCount=periodCount;
}
Mr Ms;
}
static Me ma_device_data_loop__dsound(ma_device*Md)
{
Me Mf=Ms;
M3 bpfDeviceCapture=ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
M3 bpfDevicePlayback=ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
HRESULT hr;
DWORD lockOffsetInBytesCapture;
DWORD lockSizeInBytesCapture;
DWORD mappedSizeInBytesCapture;
DWORD mappedDeviceFramesProcessedCapture;
Mv*pMappedDeviceBufferCapture;
DWORD lockOffsetInBytesPlayback;
DWORD lockSizeInBytesPlayback;
DWORD mappedSizeInBytesPlayback;
Mv*pMappedDeviceBufferPlayback;
DWORD prevReadCursorInBytesCapture=0;
DWORD prevPlayCursorInBytesPlayback=0;
ma_bool32 physicalPlayCursorLoopFlagPlayback=0;
DWORD virtualWriteCursorInBytesPlayback=0;
ma_bool32 virtualWriteCursorLoopFlagPlayback=0;
ma_bool32 isPlaybackDeviceStarted=MA_FALSE;
M3 framesWrittenToPlaybackDevice=0;
M3 waitTimeInMilliseconds=1;
DWORD playbackBufferStatus=0;
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
hr=ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,MA_DSCBSTART_LOOPING);
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.");
Mr ma_result_from_HRESULT(hr);
}
}
while (ma_device_get_state(Md)==ma_device_state_started) {
switch (Md->type)
{
case ma_device_type_duplex:
{
DWORD physicalCaptureCursorInBytes;
DWORD physicalReadCursorInBytes;
hr=ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,&physicalCaptureCursorInBytes,&physicalReadCursorInBytes);
if (FAILED(hr)) {
 Mr ma_result_from_HRESULT(hr);
}
if (physicalReadCursorInBytes==prevReadCursorInBytesCapture) {
 ma_sleep(waitTimeInMilliseconds);
 continue;
}
if (prevReadCursorInBytesCapture<physicalReadCursorInBytes) {
 lockOffsetInBytesCapture=prevReadCursorInBytesCapture;
 lockSizeInBytesCapture=(physicalReadCursorInBytes-prevReadCursorInBytesCapture);
} else {
 if (prevReadCursorInBytesCapture<Md->capture.internalPeriodSizeInFrames*Md->capture.internalPeriods*bpfDeviceCapture) {
 lockOffsetInBytesCapture=prevReadCursorInBytesCapture;
 lockSizeInBytesCapture=(Md->capture.internalPeriodSizeInFrames*Md->capture.internalPeriods*bpfDeviceCapture)-prevReadCursorInBytesCapture;
 } else {
 lockOffsetInBytesCapture=0;
 lockSizeInBytesCapture=physicalReadCursorInBytes;
 }
}
if (lockSizeInBytesCapture==0) {
 ma_sleep(waitTimeInMilliseconds);
 continue;
}
hr=ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,lockOffsetInBytesCapture,lockSizeInBytesCapture,&pMappedDeviceBufferCapture,&mappedSizeInBytesCapture,NULL,NULL,0);
if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.");
 Mr ma_result_from_HRESULT(hr);
}
mappedDeviceFramesProcessedCapture=0;
for (;;) {
 ma_uint8 inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
 M3 inputFramesInClientFormatCap=sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh);
 ma_uint8 outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
 M3 outputFramesInClientFormatCap=sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(Md->playback.format,Md->playback.Mh);
 M3 outputFramesInClientFormatCount;
 M3 outputFramesInClientFormatConsumed=0;
 M6 clientCapturedFramesToProcess=ma_min(inputFramesInClientFormatCap,outputFramesInClientFormatCap);
 M6 deviceCapturedFramesToProcess=(mappedSizeInBytesCapture / bpfDeviceCapture)-mappedDeviceFramesProcessedCapture;
 Mv*pRunningMappedDeviceBufferCapture=ma_offset_ptr(pMappedDeviceBufferCapture,mappedDeviceFramesProcessedCapture*bpfDeviceCapture);
 Mf=ma_data_converter_process_pcm_frames(&Md->capture.converter,pRunningMappedDeviceBufferCapture,&deviceCapturedFramesToProcess,inputFramesInClientFormat,&clientCapturedFramesToProcess);
 if (Mf !=Ms) {
 break;
 }
 outputFramesInClientFormatCount=(M3)clientCapturedFramesToProcess;
 mappedDeviceFramesProcessedCapture+=(M3)deviceCapturedFramesToProcess;
 ma_device__handle_data_callback(Md,outputFramesInClientFormat,inputFramesInClientFormat,(M3)clientCapturedFramesToProcess);
 for (;;) {
 M3 framesWrittenThisIteration;
 DWORD physicalPlayCursorInBytes;
 DWORD physicalWriteCursorInBytes;
 DWORD availableBytesPlayback;
 DWORD silentPaddingInBytes=0;
 if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,&physicalPlayCursorInBytes,&physicalWriteCursorInBytes))) {
 break;
 }
 if (physicalPlayCursorInBytes<prevPlayCursorInBytesPlayback) {
 physicalPlayCursorLoopFlagPlayback=!physicalPlayCursorLoopFlagPlayback;
 }
 prevPlayCursorInBytesPlayback=physicalPlayCursorInBytes;
 if (physicalPlayCursorLoopFlagPlayback==virtualWriteCursorLoopFlagPlayback) {
 if (physicalPlayCursorInBytes<=virtualWriteCursorInBytesPlayback) {
 availableBytesPlayback=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)-virtualWriteCursorInBytesPlayback;
 availableBytesPlayback+=physicalPlayCursorInBytes;
 } else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Play cursor has moved in front of the write cursor (same loop iteration). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
 availableBytesPlayback=0;
 }
 } else {
 if (physicalPlayCursorInBytes>=virtualWriteCursorInBytesPlayback) {
 availableBytesPlayback=physicalPlayCursorInBytes-virtualWriteCursorInBytesPlayback;
 } else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
 availableBytesPlayback=0;
 }
 }
 if (availableBytesPlayback==0) {
 if (!isPlaybackDeviceStarted) {
 hr=ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,0,0,MA_DSBPLAY_LOOPING);
 if (FAILED(hr)) {
 ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer);
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
 Mr ma_result_from_HRESULT(hr);
 }
 isPlaybackDeviceStarted=MA_TRUE;
 } else {
 ma_sleep(waitTimeInMilliseconds);
 continue;
 }
 }
 lockOffsetInBytesPlayback=virtualWriteCursorInBytesPlayback;
 if (physicalPlayCursorLoopFlagPlayback==virtualWriteCursorLoopFlagPlayback) {
 lockSizeInBytesPlayback=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)-virtualWriteCursorInBytesPlayback;
 } else {
 lockSizeInBytesPlayback=physicalPlayCursorInBytes-virtualWriteCursorInBytesPlayback;
 }
 hr=ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,lockOffsetInBytesPlayback,lockSizeInBytesPlayback,&pMappedDeviceBufferPlayback,&mappedSizeInBytesPlayback,NULL,NULL,0);
 if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.");
 Mf=ma_result_from_HRESULT(hr);
 break;
 }
 if (isPlaybackDeviceStarted) {
 DWORD bytesQueuedForPlayback=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)-availableBytesPlayback;
 if (bytesQueuedForPlayback<(Md->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) {
 silentPaddingInBytes=(Md->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback)-bytesQueuedForPlayback;
 if (silentPaddingInBytes>lockSizeInBytesPlayback) {
 silentPaddingInBytes=lockSizeInBytesPlayback;
 }
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes);
 }
 }
 if (silentPaddingInBytes>0) {
 MA_ZERO_MEMORY(pMappedDeviceBufferPlayback,silentPaddingInBytes);
 framesWrittenThisIteration=silentPaddingInBytes/bpfDevicePlayback;
 } else {
 M6 convertedFrameCountIn=(outputFramesInClientFormatCount-outputFramesInClientFormatConsumed);
 M6 convertedFrameCountOut=mappedSizeInBytesPlayback/bpfDevicePlayback;
 Mv*pConvertedFramesIn=ma_offset_ptr(outputFramesInClientFormat,outputFramesInClientFormatConsumed*bpfDevicePlayback);
 Mv*pConvertedFramesOut=pMappedDeviceBufferPlayback;
 Mf=ma_data_converter_process_pcm_frames(&Md->playback.converter,pConvertedFramesIn,&convertedFrameCountIn,pConvertedFramesOut,&convertedFrameCountOut);
 if (Mf !=Ms) {
 break;
 }
 outputFramesInClientFormatConsumed+=(M3)convertedFrameCountOut;
 framesWrittenThisIteration=(M3)convertedFrameCountOut;
 }
 hr=ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,pMappedDeviceBufferPlayback,framesWrittenThisIteration*bpfDevicePlayback,NULL,0);
 if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.");
 Mf=ma_result_from_HRESULT(hr);
 break;
 }
 virtualWriteCursorInBytesPlayback+=framesWrittenThisIteration*bpfDevicePlayback;
 if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback)==Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods) {
 virtualWriteCursorInBytesPlayback=0;
 virtualWriteCursorLoopFlagPlayback=!virtualWriteCursorLoopFlagPlayback;
 }
 framesWrittenToPlaybackDevice+=framesWrittenThisIteration;
 if (!isPlaybackDeviceStarted&&framesWrittenToPlaybackDevice>=(Md->playback.internalPeriodSizeInFrames*2)) {
 hr=ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,0,0,MA_DSBPLAY_LOOPING);
 if (FAILED(hr)) {
 ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer);
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
 Mr ma_result_from_HRESULT(hr);
 }
 isPlaybackDeviceStarted=MA_TRUE;
 }
 if (framesWrittenThisIteration<mappedSizeInBytesPlayback/bpfDevicePlayback) {
 break;
 }
 }
 if (clientCapturedFramesToProcess==0) {
 break;
 }
}
hr=ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,pMappedDeviceBufferCapture,mappedSizeInBytesCapture,NULL,0);
if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.");
 Mr ma_result_from_HRESULT(hr);
}
prevReadCursorInBytesCapture=(lockOffsetInBytesCapture+mappedSizeInBytesCapture);
} break;
case ma_device_type_capture:
{
DWORD physicalCaptureCursorInBytes;
DWORD physicalReadCursorInBytes;
hr=ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,&physicalCaptureCursorInBytes,&physicalReadCursorInBytes);
if (FAILED(hr)) {
 Mr MA_ERROR;
}
if (prevReadCursorInBytesCapture==physicalReadCursorInBytes) {
 ma_sleep(waitTimeInMilliseconds);
 continue;
}
if (prevReadCursorInBytesCapture<physicalReadCursorInBytes) {
 lockOffsetInBytesCapture=prevReadCursorInBytesCapture;
 lockSizeInBytesCapture=(physicalReadCursorInBytes-prevReadCursorInBytesCapture);
} else {
 if (prevReadCursorInBytesCapture<Md->capture.internalPeriodSizeInFrames*Md->capture.internalPeriods*bpfDeviceCapture) {
 lockOffsetInBytesCapture=prevReadCursorInBytesCapture;
 lockSizeInBytesCapture=(Md->capture.internalPeriodSizeInFrames*Md->capture.internalPeriods*bpfDeviceCapture)-prevReadCursorInBytesCapture;
 } else {
 lockOffsetInBytesCapture=0;
 lockSizeInBytesCapture=physicalReadCursorInBytes;
 }
}
if (lockSizeInBytesCapture<Md->capture.internalPeriodSizeInFrames) {
 ma_sleep(waitTimeInMilliseconds);
 continue;
}
hr=ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,lockOffsetInBytesCapture,lockSizeInBytesCapture,&pMappedDeviceBufferCapture,&mappedSizeInBytesCapture,NULL,NULL,0);
if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.");
 Mf=ma_result_from_HRESULT(hr);
}
if (lockSizeInBytesCapture !=mappedSizeInBytesCapture) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
}
ma_device__send_frames_to_client(Md,mappedSizeInBytesCapture/bpfDeviceCapture,pMappedDeviceBufferCapture);
hr=ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer,pMappedDeviceBufferCapture,mappedSizeInBytesCapture,NULL,0);
if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.");
 Mr ma_result_from_HRESULT(hr);
}
prevReadCursorInBytesCapture=lockOffsetInBytesCapture+mappedSizeInBytesCapture;
if (prevReadCursorInBytesCapture==(Md->capture.internalPeriodSizeInFrames*Md->capture.internalPeriods*bpfDeviceCapture)) {
 prevReadCursorInBytesCapture=0;
}
} break;
case Mt:
{
DWORD availableBytesPlayback;
DWORD physicalPlayCursorInBytes;
DWORD physicalWriteCursorInBytes;
hr=ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,&physicalPlayCursorInBytes,&physicalWriteCursorInBytes);
if (FAILED(hr)) {
 break;
}
hr=ma_IDirectSoundBuffer_GetStatus((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,&playbackBufferStatus);
if (SUCCEEDED(hr)&&(playbackBufferStatus&MA_DSBSTATUS_PLAYING)==0&&isPlaybackDeviceStarted) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[DirectSound] Attempting to resume audio due to state: %d.", (int)playbackBufferStatus);
 hr=ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,0,0,MA_DSBPLAY_LOOPING);
 if (FAILED(hr)) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed after attempting to resume from state %d.", (int)playbackBufferStatus);
 Mr ma_result_from_HRESULT(hr);
 }
 isPlaybackDeviceStarted=MA_TRUE;
 ma_sleep(waitTimeInMilliseconds);
 continue;
}
if (physicalPlayCursorInBytes<prevPlayCursorInBytesPlayback) {
 physicalPlayCursorLoopFlagPlayback=!physicalPlayCursorLoopFlagPlayback;
}
prevPlayCursorInBytesPlayback=physicalPlayCursorInBytes;
if (physicalPlayCursorLoopFlagPlayback==virtualWriteCursorLoopFlagPlayback) {
 if (physicalPlayCursorInBytes<=virtualWriteCursorInBytesPlayback) {
 availableBytesPlayback=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)-virtualWriteCursorInBytesPlayback;
 availableBytesPlayback+=physicalPlayCursorInBytes;
 } else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
 availableBytesPlayback=0;
 }
} else {
 if (physicalPlayCursorInBytes>=virtualWriteCursorInBytesPlayback) {
 availableBytesPlayback=physicalPlayCursorInBytes-virtualWriteCursorInBytesPlayback;
 } else {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[DirectSound] (Playback): Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
 availableBytesPlayback=0;
 }
}
if (availableBytesPlayback<Md->playback.internalPeriodSizeInFrames) {
 if (availableBytesPlayback==0&&!isPlaybackDeviceStarted) {
 hr=ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,0,0,MA_DSBPLAY_LOOPING);
 if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
 Mr ma_result_from_HRESULT(hr);
 }
 isPlaybackDeviceStarted=MA_TRUE;
 } else {
 ma_sleep(waitTimeInMilliseconds);
 continue;
 }
}
lockOffsetInBytesPlayback=virtualWriteCursorInBytesPlayback;
if (physicalPlayCursorLoopFlagPlayback==virtualWriteCursorLoopFlagPlayback) {
 lockSizeInBytesPlayback=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)-virtualWriteCursorInBytesPlayback;
} else {
 lockSizeInBytesPlayback=physicalPlayCursorInBytes-virtualWriteCursorInBytesPlayback;
}
hr=ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,lockOffsetInBytesPlayback,lockSizeInBytesPlayback,&pMappedDeviceBufferPlayback,&mappedSizeInBytesPlayback,NULL,NULL,0);
if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.");
 Mf=ma_result_from_HRESULT(hr);
 break;
}
ma_device__read_frames_from_client(Md,(mappedSizeInBytesPlayback/bpfDevicePlayback),pMappedDeviceBufferPlayback);
hr=ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,pMappedDeviceBufferPlayback,mappedSizeInBytesPlayback,NULL,0);
if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.");
 Mf=ma_result_from_HRESULT(hr);
 break;
}
virtualWriteCursorInBytesPlayback+=mappedSizeInBytesPlayback;
if (virtualWriteCursorInBytesPlayback==Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback) {
 virtualWriteCursorInBytesPlayback=0;
 virtualWriteCursorLoopFlagPlayback=!virtualWriteCursorLoopFlagPlayback;
}
framesWrittenToPlaybackDevice+=mappedSizeInBytesPlayback/bpfDevicePlayback;
if (!isPlaybackDeviceStarted&&framesWrittenToPlaybackDevice>=Md->playback.internalPeriodSizeInFrames) {
 hr=ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,0,0,MA_DSBPLAY_LOOPING);
 if (FAILED(hr)) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
 Mr ma_result_from_HRESULT(hr);
 }
 isPlaybackDeviceStarted=MA_TRUE;
}
} break;
default:Mr MA_INVALID_ARGS;
}
if (Mf !=Ms) {
Mr Mf;
}
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
hr=ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)Md->dsound.pCaptureBuffer);
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.");
Mr ma_result_from_HRESULT(hr);
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
if (isPlaybackDeviceStarted) {
for (;;) {
DWORD availableBytesPlayback=0;
DWORD physicalPlayCursorInBytes;
DWORD physicalWriteCursorInBytes;
hr=ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,&physicalPlayCursorInBytes,&physicalWriteCursorInBytes);
if (FAILED(hr)) {
 break;
}
if (physicalPlayCursorInBytes<prevPlayCursorInBytesPlayback) {
 physicalPlayCursorLoopFlagPlayback=!physicalPlayCursorLoopFlagPlayback;
}
prevPlayCursorInBytesPlayback=physicalPlayCursorInBytes;
if (physicalPlayCursorLoopFlagPlayback==virtualWriteCursorLoopFlagPlayback) {
 if (physicalPlayCursorInBytes<=virtualWriteCursorInBytesPlayback) {
 availableBytesPlayback=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)-virtualWriteCursorInBytesPlayback;
 availableBytesPlayback+=physicalPlayCursorInBytes;
 } else {
 break;
 }
} else {
 if (physicalPlayCursorInBytes>=virtualWriteCursorInBytesPlayback) {
 availableBytesPlayback=physicalPlayCursorInBytes-virtualWriteCursorInBytesPlayback;
 } else {
 break;
 }
}
if (availableBytesPlayback>=(Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*bpfDevicePlayback)) {
 break;
}
ma_sleep(waitTimeInMilliseconds);
}
}
hr=ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer);
if (FAILED(hr)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.");
Mr ma_result_from_HRESULT(hr);
}
ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)Md->dsound.pPlaybackBuffer,0);
}
Mr Ms;
}
static Me ma_context_uninit__dsound(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_dsound);
ma_dlclose(ma_context_get_log(Mc),Mc->dsound.hDSoundDLL);
Mr Ms;
}
static Me ma_context_init__dsound(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
Mc->dsound.hDSoundDLL = ma_dlopen(ma_context_get_log(Mc), "dsound.dll");
if (Mc->dsound.hDSoundDLL==NULL) {
Mr MA_API_NOT_FOUND;
}
Mc->dsound.DirectSoundCreate = ma_dlsym(ma_context_get_log(Mc), Mc->dsound.hDSoundDLL, "DirectSoundCreate");
Mc->dsound.DirectSoundEnumerateA = ma_dlsym(ma_context_get_log(Mc), Mc->dsound.hDSoundDLL, "DirectSoundEnumerateA");
Mc->dsound.DirectSoundCaptureCreate = ma_dlsym(ma_context_get_log(Mc), Mc->dsound.hDSoundDLL, "DirectSoundCaptureCreate");
Mc->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(ma_context_get_log(Mc), Mc->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA");
if (Mc->dsound.DirectSoundCreate==NULL||
Mc->dsound.DirectSoundEnumerateA==NULL||
Mc->dsound.DirectSoundCaptureCreate==NULL||
Mc->dsound.DirectSoundCaptureEnumerateA==NULL) {
Mr MA_API_NOT_FOUND;
}
Mc->dsound.hWnd=Mo->dsound.hWnd;
pCallbacks->onContextInit=ma_context_init__dsound;
pCallbacks->onContextUninit=ma_context_uninit__dsound;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__dsound;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__dsound;
pCallbacks->onDeviceInit=ma_device_init__dsound;
pCallbacks->onDeviceUninit=ma_device_uninit__dsound;
pCallbacks->onDeviceStart=NULL;
pCallbacks->onDeviceStop=NULL;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=ma_device_data_loop__dsound;
Mr Ms;
}
#endif
#ifdef MA_HAS_WINMM
#define MA_MMSYSERR_NOERROR 0
#define MA_MMSYSERR_ERROR 1
#define MA_MMSYSERR_BADDEVICEID 2
#define MA_MMSYSERR_INVALHANDLE 5
#define MA_MMSYSERR_NOMEM 7
#define MA_MMSYSERR_INVALFLAG 10
#define MA_MMSYSERR_INVALPARAM 11
#define MA_MMSYSERR_HANDLEBUSY 12
#define MA_CALLBACK_EVENT 0x00050000
#define MA_WAVE_ALLOWSYNC 0x0002
#define MA_WHDR_DONE 0x00000001
#define MA_WHDR_PREPARED 0x00000002
#define MA_WHDR_BEGINLOOP 0x00000004
#define MA_WHDR_ENDLOOP 0x00000008
#define MA_WHDR_INQUEUE 0x00000010
#define MA_MAXPNAMELEN 32
typedef Mv*MA_HWAVEIN;
typedef Mv*MA_HWAVEOUT;
typedef UINT MA_MMRESULT;
typedef UINT MA_MMVERSION;
typedef struct
{
WORD wMid;
WORD wPid;
MA_MMVERSION vDriverVersion;
CHAR szPname[MA_MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
} MA_WAVEINCAPSA;
typedef struct
{
WORD wMid;
WORD wPid;
MA_MMVERSION vDriverVersion;
CHAR szPname[MA_MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
DWORD dwSupport;
} MA_WAVEOUTCAPSA;
typedef struct tagWAVEHDR
{
char*lpData;
DWORD dwBufferLength;
DWORD dwBytesRecorded;
DWORD_PTR dwUser;
DWORD dwFlags;
DWORD dwLoops;
struct tagWAVEHDR*lpNext;
DWORD_PTR reserved;
} MA_WAVEHDR;
typedef struct
{
WORD wMid;
WORD wPid;
MA_MMVERSION vDriverVersion;
CHAR szPname[MA_MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
DWORD dwSupport;
GUID ManufacturerGuid;
GUID ProductGuid;
GUID NameGuid;
} MA_WAVEOUTCAPS2A;
typedef struct
{
WORD wMid;
WORD wPid;
MA_MMVERSION vDriverVersion;
CHAR szPname[MA_MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
GUID ManufacturerGuid;
GUID ProductGuid;
GUID NameGuid;
} MA_WAVEINCAPS2A;
typedef UINT (WINAPI*MA_PFN_waveOutGetNumDevs)(Mv);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID,MA_WAVEOUTCAPSA*pwoc,UINT cbwoc);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutOpen)(MA_HWAVEOUT*phwo,UINT uDeviceID,const MA_WAVEFORMATEX*pwfx,DWORD_PTR dwCallback,DWORD_PTR dwInstance,DWORD fdwOpen);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutClose)(MA_HWAVEOUT hwo);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutPrepareHeader)(MA_HWAVEOUT hwo,MA_WAVEHDR*pwh,UINT cbwh);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutUnprepareHeader)(MA_HWAVEOUT hwo,MA_WAVEHDR*pwh,UINT cbwh);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutWrite)(MA_HWAVEOUT hwo,MA_WAVEHDR*pwh,UINT cbwh);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveOutReset)(MA_HWAVEOUT hwo);
typedef UINT (WINAPI*MA_PFN_waveInGetNumDevs)(Mv);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID,MA_WAVEINCAPSA*pwic,UINT cbwic);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInOpen)(MA_HWAVEIN*phwi,UINT uDeviceID,const MA_WAVEFORMATEX*pwfx,DWORD_PTR dwCallback,DWORD_PTR dwInstance,DWORD fdwOpen);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInClose)(MA_HWAVEIN hwi);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInPrepareHeader)(MA_HWAVEIN hwi,MA_WAVEHDR*pwh,UINT cbwh);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInUnprepareHeader)(MA_HWAVEIN hwi,MA_WAVEHDR*pwh,UINT cbwh);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInAddBuffer)(MA_HWAVEIN hwi,MA_WAVEHDR*pwh,UINT cbwh);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInStart)(MA_HWAVEIN hwi);
typedef MA_MMRESULT (WINAPI*MA_PFN_waveInReset)(MA_HWAVEIN hwi);
static Me ma_result_from_MMRESULT(MA_MMRESULT resultMM)
{
switch (resultMM)
{
case MA_MMSYSERR_NOERROR:Mr Ms;
case MA_MMSYSERR_BADDEVICEID:Mr MA_INVALID_ARGS;
case MA_MMSYSERR_INVALHANDLE:Mr MA_INVALID_ARGS;
case MA_MMSYSERR_NOMEM:Mr MA_OUT_OF_MEMORY;
case MA_MMSYSERR_INVALFLAG:Mr MA_INVALID_ARGS;
case MA_MMSYSERR_INVALPARAM:Mr MA_INVALID_ARGS;
case MA_MMSYSERR_HANDLEBUSY:Mr MA_BUSY;
case MA_MMSYSERR_ERROR:Mr MA_ERROR;
default:Mr MA_ERROR;
}
}
static char*ma_find_last_character(char*str,char ch)
{
char*last;
if (str==NULL) {
Mr NULL;
}
last=NULL;
while (*str !='\0') {
if (*str==ch) {
last=str;
}
str+=1;
}
Mr last;
}
static M3 ma_get_period_size_in_bytes(M3 periodSizeInFrames,ma_format format,M3 Mh)
{
Mr periodSizeInFrames*ma_get_bytes_per_frame(format,Mh);
}
typedef struct
{
CHAR szPname[MA_MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
GUID NameGuid;
} MA_WAVECAPSA;
static Me ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats,WORD Mh,WORD*pBitsPerSample,DWORD*pSampleRate)
{
WORD bitsPerSample=0;
DWORD sampleRate=0;
if (pBitsPerSample) {
*pBitsPerSample=0;
}
if (pSampleRate) {
*pSampleRate=0;
}
if (Mh==1) {
bitsPerSample=16;
if ((dwFormats&WAVE_FORMAT_48M16) !=0) {
sampleRate=48000;
} else if ((dwFormats&WAVE_FORMAT_44M16) !=0) {
sampleRate=44100;
} else if ((dwFormats&WAVE_FORMAT_2M16) !=0) {
sampleRate=22050;
} else if ((dwFormats&WAVE_FORMAT_1M16) !=0) {
sampleRate=11025;
} else if ((dwFormats&WAVE_FORMAT_96M16) !=0) {
sampleRate=96000;
} else {
bitsPerSample=8;
if ((dwFormats&WAVE_FORMAT_48M08) !=0) {
sampleRate=48000;
} else if ((dwFormats&WAVE_FORMAT_44M08) !=0) {
sampleRate=44100;
} else if ((dwFormats&WAVE_FORMAT_2M08) !=0) {
sampleRate=22050;
} else if ((dwFormats&WAVE_FORMAT_1M08) !=0) {
sampleRate=11025;
} else if ((dwFormats&WAVE_FORMAT_96M08) !=0) {
sampleRate=96000;
} else {
Mr MA_FORMAT_NOT_SUPPORTED;
}
}
} else {
bitsPerSample=16;
if ((dwFormats&WAVE_FORMAT_48S16) !=0) {
sampleRate=48000;
} else if ((dwFormats&WAVE_FORMAT_44S16) !=0) {
sampleRate=44100;
} else if ((dwFormats&WAVE_FORMAT_2S16) !=0) {
sampleRate=22050;
} else if ((dwFormats&WAVE_FORMAT_1S16) !=0) {
sampleRate=11025;
} else if ((dwFormats&WAVE_FORMAT_96S16) !=0) {
sampleRate=96000;
} else {
bitsPerSample=8;
if ((dwFormats&WAVE_FORMAT_48S08) !=0) {
sampleRate=48000;
} else if ((dwFormats&WAVE_FORMAT_44S08) !=0) {
sampleRate=44100;
} else if ((dwFormats&WAVE_FORMAT_2S08) !=0) {
sampleRate=22050;
} else if ((dwFormats&WAVE_FORMAT_1S08) !=0) {
sampleRate=11025;
} else if ((dwFormats&WAVE_FORMAT_96S08) !=0) {
sampleRate=96000;
} else {
Mr MA_FORMAT_NOT_SUPPORTED;
}
}
}
if (pBitsPerSample) {
*pBitsPerSample=bitsPerSample;
}
if (pSampleRate) {
*pSampleRate=sampleRate;
}
Mr Ms;
}
static Me ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats,WORD Mh,MA_WAVEFORMATEX*pWF)
{
Me Mf;
MA_ASSERT(pWF !=NULL);
MA_ZERO_OBJECT(pWF);
pWF->cbSize=sizeof(*pWF);
pWF->wFormatTag=WAVE_FORMAT_PCM;
pWF->nChannels=(WORD)Mh;
if (pWF->nChannels>2) {
pWF->nChannels=2;
}
Mf=ma_get_best_info_from_formats_flags__winmm(dwFormats,Mh,&pWF->wBitsPerSample,&pWF->nSamplesPerSec);
if (Mf !=Ms) {
Mr Mf;
}
pWF->nBlockAlign=(WORD)(pWF->nChannels*pWF->wBitsPerSample / 8);
pWF->nAvgBytesPerSec=pWF->nBlockAlign*pWF->nSamplesPerSec;
Mr Ms;
}
static Me ma_context_get_device_info_from_WAVECAPS(ma_context*Mc,MA_WAVECAPSA*pCaps,ma_device_info*pDeviceInfo)
{
WORD bitsPerSample;
DWORD sampleRate;
Me Mf;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pCaps !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),pCaps->szPname,(size_t)-1);
if (!ma_is_guid_null(&pCaps->NameGuid)) {
WCHAR guidStrW[256];
if (((MA_PFN_StringFromGUID2)Mc->win32.StringFromGUID2)(&pCaps->NameGuid,guidStrW,ma_countof(guidStrW))>0) {
char guidStr[256];
char keyStr[1024];
HKEY hKey;
WideCharToMultiByte(CP_UTF8,0,guidStrW,-1,guidStr,sizeof(guidStr),0,FALSE);
ma_strcpy_s(keyStr, sizeof(keyStr), "SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
ma_strcat_s(keyStr,sizeof(keyStr),guidStr);
if (((MA_PFN_RegOpenKeyExA)Mc->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE,keyStr,0,KEY_READ,&hKey)==ERROR_SUCCESS) {
BYTE nameFromReg[512];
DWORD nameFromRegSize=sizeof(nameFromReg);
LONG resultWin32 = ((MA_PFN_RegQueryValueExA)Mc->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (BYTE*)nameFromReg, (DWORD*)&nameFromRegSize);
((MA_PFN_RegCloseKey)Mc->win32.RegCloseKey)(hKey);
if (resultWin32==ERROR_SUCCESS) {
 char name[1024];
 if (ma_strcpy_s(name,sizeof(name),pDeviceInfo->name)==0) {
 char*nameBeg=ma_find_last_character(name,'(');
 if (nameBeg !=NULL) {
 size_t leadingLen=(nameBeg-name);
 ma_strncpy_s(nameBeg+1,sizeof(name)-leadingLen,(const char*)nameFromReg,(size_t)-1);
 if (leadingLen+nameFromRegSize<sizeof(name)-1) {
 ma_strcat_s(name, sizeof(name), ")");
 }
 ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),name,(size_t)-1);
 }
 }
}
}
}
}
Mf=ma_get_best_info_from_formats_flags__winmm(pCaps->dwFormats,pCaps->wChannels,&bitsPerSample,&sampleRate);
if (Mf !=Ms) {
Mr Mf;
}
if (bitsPerSample==8) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_u8;
} else if (bitsPerSample==16) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_s16;
} else if (bitsPerSample==24) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_s24;
} else if (bitsPerSample==32) {
pDeviceInfo->nativeDataFormats[0].format=ma_format_s32;
} else {
Mr MA_FORMAT_NOT_SUPPORTED;
}
pDeviceInfo->nativeDataFormats[0].Mh=pCaps->wChannels;
pDeviceInfo->nativeDataFormats[0].sampleRate=sampleRate;
pDeviceInfo->nativeDataFormats[0].flags=0;
pDeviceInfo->nativeDataFormatCount=1;
Mr Ms;
}
static Me ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context*Mc,MA_WAVEOUTCAPS2A*pCaps,ma_device_info*pDeviceInfo)
{
MA_WAVECAPSA caps;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pCaps !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
MA_COPY_MEMORY(caps.szPname,pCaps->szPname,sizeof(caps.szPname));
caps.dwFormats=pCaps->dwFormats;
caps.wChannels=pCaps->wChannels;
caps.NameGuid=pCaps->NameGuid;
Mr ma_context_get_device_info_from_WAVECAPS(Mc,&caps,pDeviceInfo);
}
static Me ma_context_get_device_info_from_WAVEINCAPS2(ma_context*Mc,MA_WAVEINCAPS2A*pCaps,ma_device_info*pDeviceInfo)
{
MA_WAVECAPSA caps;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pCaps !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
MA_COPY_MEMORY(caps.szPname,pCaps->szPname,sizeof(caps.szPname));
caps.dwFormats=pCaps->dwFormats;
caps.wChannels=pCaps->wChannels;
caps.NameGuid=pCaps->NameGuid;
Mr ma_context_get_device_info_from_WAVECAPS(Mc,&caps,pDeviceInfo);
}
static Me ma_context_enumerate_devices__winmm(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
UINT playbackDeviceCount;
UINT captureDeviceCount;
UINT iPlaybackDevice;
UINT iCaptureDevice;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
playbackDeviceCount=((MA_PFN_waveOutGetNumDevs)Mc->winmm.waveOutGetNumDevs)();
for (iPlaybackDevice=0; iPlaybackDevice<playbackDeviceCount;++iPlaybackDevice) {
MA_MMRESULT Mf;
MA_WAVEOUTCAPS2A caps;
MA_ZERO_OBJECT(&caps);
Mf=((MA_PFN_waveOutGetDevCapsA)Mc->winmm.waveOutGetDevCapsA)(iPlaybackDevice,(MA_WAVEOUTCAPSA*)&caps,sizeof(caps));
if (Mf==MA_MMSYSERR_NOERROR) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.winmm=iPlaybackDevice;
if (iPlaybackDevice==0) {
deviceInfo.isDefault=MA_TRUE;
}
if (ma_context_get_device_info_from_WAVEOUTCAPS2(Mc,&caps,&deviceInfo)==Ms) {
ma_bool32 cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
if (cbResult==MA_FALSE) {
 Mr Ms;
}
}
}
}
captureDeviceCount=((MA_PFN_waveInGetNumDevs)Mc->winmm.waveInGetNumDevs)();
for (iCaptureDevice=0; iCaptureDevice<captureDeviceCount;++iCaptureDevice) {
MA_MMRESULT Mf;
MA_WAVEINCAPS2A caps;
MA_ZERO_OBJECT(&caps);
Mf=((MA_PFN_waveInGetDevCapsA)Mc->winmm.waveInGetDevCapsA)(iCaptureDevice,(MA_WAVEINCAPSA*)&caps,sizeof(caps));
if (Mf==MA_MMSYSERR_NOERROR) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.winmm=iCaptureDevice;
if (iCaptureDevice==0) {
deviceInfo.isDefault=MA_TRUE;
}
if (ma_context_get_device_info_from_WAVEINCAPS2(Mc,&caps,&deviceInfo)==Ms) {
ma_bool32 cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
if (cbResult==MA_FALSE) {
 Mr Ms;
}
}
}
}
Mr Ms;
}
static Me ma_context_get_device_info__winmm(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
UINT winMMDeviceID;
MA_ASSERT(Mc !=NULL);
winMMDeviceID=0;
if (pDeviceID !=NULL) {
winMMDeviceID=(UINT)pDeviceID->winmm;
}
pDeviceInfo->id.winmm=winMMDeviceID;
if (winMMDeviceID==0) {
pDeviceInfo->isDefault=MA_TRUE;
}
if (deviceType==Mt) {
MA_MMRESULT Mf;
MA_WAVEOUTCAPS2A caps;
MA_ZERO_OBJECT(&caps);
Mf=((MA_PFN_waveOutGetDevCapsA)Mc->winmm.waveOutGetDevCapsA)(winMMDeviceID,(MA_WAVEOUTCAPSA*)&caps,sizeof(caps));
if (Mf==MA_MMSYSERR_NOERROR) {
Mr ma_context_get_device_info_from_WAVEOUTCAPS2(Mc,&caps,pDeviceInfo);
}
} else {
MA_MMRESULT Mf;
MA_WAVEINCAPS2A caps;
MA_ZERO_OBJECT(&caps);
Mf=((MA_PFN_waveInGetDevCapsA)Mc->winmm.waveInGetDevCapsA)(winMMDeviceID,(MA_WAVEINCAPSA*)&caps,sizeof(caps));
if (Mf==MA_MMSYSERR_NOERROR) {
Mr ma_context_get_device_info_from_WAVEINCAPS2(Mc,&caps,pDeviceInfo);
}
}
Mr MA_NO_DEVICE;
}
static Me ma_device_uninit__winmm(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
((MA_PFN_waveInClose)Md->Mc->winmm.waveInClose)((MA_HWAVEIN)Md->winmm.hDeviceCapture);
CloseHandle((HANDLE)Md->winmm.hEventCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
((MA_PFN_waveOutReset)Md->Mc->winmm.waveOutReset)((MA_HWAVEOUT)Md->winmm.hDevicePlayback);
((MA_PFN_waveOutClose)Md->Mc->winmm.waveOutClose)((MA_HWAVEOUT)Md->winmm.hDevicePlayback);
CloseHandle((HANDLE)Md->winmm.hEventPlayback);
}
ma_free(Md->winmm._pHeapData,&Md->Mc->allocationCallbacks);
MA_ZERO_OBJECT(&Md->winmm);
Mr Ms;
}
static M3 ma_calculate_period_size_in_frames_from_descriptor__winmm(const ma_device_descriptor*pDescriptor,M3 nativeSampleRate,ma_performance_profile performanceProfile)
{
M3 minPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(40,nativeSampleRate);
M3 periodSizeInFrames;
periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,nativeSampleRate,performanceProfile);
if (periodSizeInFrames<minPeriodSizeInFrames) {
periodSizeInFrames=minPeriodSizeInFrames;
}
Mr periodSizeInFrames;
}
static Me ma_device_init__winmm(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
const char* errorMsg = "";
Me errorCode=MA_ERROR;
Me Mf=Ms;
M3 heapSize;
UINT winMMDeviceIDPlayback=0;
UINT winMMDeviceIDCapture=0;
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->winmm);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->shareMode==ma_share_mode_exclusive)) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
if (Mp->pDeviceID !=NULL) {
winMMDeviceIDPlayback=(UINT)Mp->pDeviceID->winmm;
}
if (pDescriptorCapture->pDeviceID !=NULL) {
winMMDeviceIDCapture=(UINT)pDescriptorCapture->pDeviceID->winmm;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
MA_WAVEINCAPSA caps;
MA_WAVEFORMATEX wf;
MA_MMRESULT resultMM;
Md->winmm.hEventCapture=(ma_handle)CreateEventA(NULL,TRUE,TRUE,NULL);
if (Md->winmm.hEventCapture==NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueuing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error;
}
if (((MA_PFN_waveInGetDevCapsA)Md->Mc->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture,&caps,sizeof(caps)) !=MA_MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
Mf=ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats,caps.wChannels,&wf);
if (Mf !=Ms) {
errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = Mf;
goto on_error;
}
resultMM=((MA_PFN_waveInOpen)Md->Mc->winmm.waveInOpen)((MA_HWAVEIN*)&Md->winmm.hDeviceCapture,winMMDeviceIDCapture,&wf,(DWORD_PTR)Md->winmm.hEventCapture,(DWORD_PTR)Md,MA_CALLBACK_EVENT|MA_WAVE_ALLOWSYNC);
if (resultMM !=MA_MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
pDescriptorCapture->format=ma_format_from_WAVEFORMATEX(&wf);
pDescriptorCapture->Mh=wf.nChannels;
pDescriptorCapture->sampleRate=wf.nSamplesPerSec;
ma_channel_map_init_standard(ma_standard_channel_map_microsoft,pDescriptorCapture->channelMap,ma_countof(pDescriptorCapture->channelMap),pDescriptorCapture->Mh);
pDescriptorCapture->periodCount=pDescriptorCapture->periodCount;
pDescriptorCapture->periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorCapture,pDescriptorCapture->sampleRate,Mo->performanceProfile);
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
MA_WAVEOUTCAPSA caps;
MA_WAVEFORMATEX wf;
MA_MMRESULT resultMM;
Md->winmm.hEventPlayback=(ma_handle)CreateEventA(NULL,TRUE,TRUE,NULL);
if (Md->winmm.hEventPlayback==NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueuing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error;
}
if (((MA_PFN_waveOutGetDevCapsA)Md->Mc->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback,&caps,sizeof(caps)) !=MA_MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
Mf=ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats,caps.wChannels,&wf);
if (Mf !=Ms) {
errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = Mf;
goto on_error;
}
resultMM=((MA_PFN_waveOutOpen)Md->Mc->winmm.waveOutOpen)((MA_HWAVEOUT*)&Md->winmm.hDevicePlayback,winMMDeviceIDPlayback,&wf,(DWORD_PTR)Md->winmm.hEventPlayback,(DWORD_PTR)Md,MA_CALLBACK_EVENT|MA_WAVE_ALLOWSYNC);
if (resultMM !=MA_MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
Mp->format=ma_format_from_WAVEFORMATEX(&wf);
Mp->Mh=wf.nChannels;
Mp->sampleRate=wf.nSamplesPerSec;
ma_channel_map_init_standard(ma_standard_channel_map_microsoft,Mp->channelMap,ma_countof(Mp->channelMap),Mp->Mh);
Mp->periodCount=Mp->periodCount;
Mp->periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__winmm(Mp,Mp->sampleRate,Mo->performanceProfile);
}
heapSize=0;
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
heapSize+=sizeof(MA_WAVEHDR)*pDescriptorCapture->periodCount+(pDescriptorCapture->periodSizeInFrames*pDescriptorCapture->periodCount*ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh));
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
heapSize+=sizeof(MA_WAVEHDR)*Mp->periodCount+(Mp->periodSizeInFrames*Mp->periodCount*ma_get_bytes_per_frame(Mp->format,Mp->Mh));
}
Md->winmm._pHeapData=(ma_uint8*)ma_calloc(heapSize,&Md->Mc->allocationCallbacks);
if (Md->winmm._pHeapData==NULL) {
errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
goto on_error;
}
MA_ZERO_MEMORY(Md->winmm._pHeapData,heapSize);
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
M3 iPeriod;
if (Mo->deviceType==ma_device_type_capture) {
Md->winmm.pWAVEHDRCapture=Md->winmm._pHeapData;
Md->winmm.pIntermediaryBufferCapture=Md->winmm._pHeapData+(sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount));
} else {
Md->winmm.pWAVEHDRCapture=Md->winmm._pHeapData;
Md->winmm.pIntermediaryBufferCapture=Md->winmm._pHeapData+(sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount+Mp->periodCount));
}
for (iPeriod=0; iPeriod<pDescriptorCapture->periodCount;++iPeriod) {
M3 periodSizeInBytes=ma_get_period_size_in_bytes(pDescriptorCapture->periodSizeInFrames,pDescriptorCapture->format,pDescriptorCapture->Mh);
((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod].lpData=(char*)(Md->winmm.pIntermediaryBufferCapture+(periodSizeInBytes*iPeriod));
((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength=periodSizeInBytes;
((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod].dwFlags=0L;
((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod].dwLoops=0L;
((MA_PFN_waveInPrepareHeader)Md->Mc->winmm.waveInPrepareHeader)((MA_HWAVEIN)Md->winmm.hDeviceCapture,&((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod],sizeof(MA_WAVEHDR));
((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod].dwUser=0;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
M3 iPeriod;
if (Mo->deviceType==Mt) {
Md->winmm.pWAVEHDRPlayback=Md->winmm._pHeapData;
Md->winmm.pIntermediaryBufferPlayback=Md->winmm._pHeapData+(sizeof(MA_WAVEHDR)*Mp->periodCount);
} else {
Md->winmm.pWAVEHDRPlayback=Md->winmm._pHeapData+(sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount));
Md->winmm.pIntermediaryBufferPlayback=Md->winmm._pHeapData+(sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount+Mp->periodCount))+(pDescriptorCapture->periodSizeInFrames*pDescriptorCapture->periodCount*ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh));
}
for (iPeriod=0; iPeriod<Mp->periodCount;++iPeriod) {
M3 periodSizeInBytes=ma_get_period_size_in_bytes(Mp->periodSizeInFrames,Mp->format,Mp->Mh);
((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod].lpData=(char*)(Md->winmm.pIntermediaryBufferPlayback+(periodSizeInBytes*iPeriod));
((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength=periodSizeInBytes;
((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags=0L;
((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops=0L;
((MA_PFN_waveOutPrepareHeader)Md->Mc->winmm.waveOutPrepareHeader)((MA_HWAVEOUT)Md->winmm.hDevicePlayback,&((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod],sizeof(MA_WAVEHDR));
((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod].dwUser=0;
}
}
Mr Ms;
on_error:
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
if (Md->winmm.pWAVEHDRCapture !=NULL) {
M3 iPeriod;
for (iPeriod=0; iPeriod<pDescriptorCapture->periodCount;++iPeriod) {
((MA_PFN_waveInUnprepareHeader)Md->Mc->winmm.waveInUnprepareHeader)((MA_HWAVEIN)Md->winmm.hDeviceCapture,&((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod],sizeof(MA_WAVEHDR));
}
}
((MA_PFN_waveInClose)Md->Mc->winmm.waveInClose)((MA_HWAVEIN)Md->winmm.hDeviceCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
if (Md->winmm.pWAVEHDRCapture !=NULL) {
M3 iPeriod;
for (iPeriod=0; iPeriod<Mp->periodCount;++iPeriod) {
((MA_PFN_waveOutUnprepareHeader)Md->Mc->winmm.waveOutUnprepareHeader)((MA_HWAVEOUT)Md->winmm.hDevicePlayback,&((MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback)[iPeriod],sizeof(MA_WAVEHDR));
}
}
((MA_PFN_waveOutClose)Md->Mc->winmm.waveOutClose)((MA_HWAVEOUT)Md->winmm.hDevicePlayback);
}
ma_free(Md->winmm._pHeapData,&Md->Mc->allocationCallbacks);
if (errorMsg !=NULL&&errorMsg[0] !='\0') {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "%s", errorMsg);
}
Mr errorCode;
}
static Me ma_device_start__winmm(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
MA_MMRESULT resultMM;
MA_WAVEHDR*pWAVEHDR;
M3 iPeriod;
pWAVEHDR=(MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture;
ResetEvent((HANDLE)Md->winmm.hEventCapture);
for (iPeriod=0; iPeriod<Md->capture.internalPeriods;++iPeriod) {
resultMM=((MA_PFN_waveInAddBuffer)Md->Mc->winmm.waveInAddBuffer)((MA_HWAVEIN)Md->winmm.hDeviceCapture,&((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[iPeriod],sizeof(MA_WAVEHDR));
if (resultMM !=MA_MMSYSERR_NOERROR) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.");
Mr ma_result_from_MMRESULT(resultMM);
}
pWAVEHDR[iPeriod].dwUser=1;
}
resultMM=((MA_PFN_waveInStart)Md->Mc->winmm.waveInStart)((MA_HWAVEIN)Md->winmm.hDeviceCapture);
if (resultMM !=MA_MMSYSERR_NOERROR) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.");
Mr ma_result_from_MMRESULT(resultMM);
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
}
Mr Ms;
}
static Me ma_device_stop__winmm(ma_device*Md)
{
MA_MMRESULT resultMM;
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
if (Md->winmm.hDeviceCapture==NULL) {
Mr MA_INVALID_ARGS;
}
resultMM=((MA_PFN_waveInReset)Md->Mc->winmm.waveInReset)((MA_HWAVEIN)Md->winmm.hDeviceCapture);
if (resultMM !=MA_MMSYSERR_NOERROR) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset capture device.");
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
M3 iPeriod;
MA_WAVEHDR*pWAVEHDR;
if (Md->winmm.hDevicePlayback==NULL) {
Mr MA_INVALID_ARGS;
}
pWAVEHDR=(MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback;
for (iPeriod=0; iPeriod<Md->playback.internalPeriods; iPeriod+=1) {
if (pWAVEHDR[iPeriod].dwUser==1) {
if (WaitForSingleObject((HANDLE)Md->winmm.hEventPlayback,INFINITE) !=WAIT_OBJECT_0) {
 break;
}
pWAVEHDR[iPeriod].dwUser=0;
}
}
resultMM=((MA_PFN_waveOutReset)Md->Mc->winmm.waveOutReset)((MA_HWAVEOUT)Md->winmm.hDevicePlayback);
if (resultMM !=MA_MMSYSERR_NOERROR) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset playback device.");
}
}
Mr Ms;
}
static Me ma_device_write__winmm(ma_device*Md,const Mv*pPCMFrames,M3 frameCount,M3*pFramesWritten)
{
Me Mf=Ms;
MA_MMRESULT resultMM;
M3 totalFramesWritten;
MA_WAVEHDR*pWAVEHDR;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pPCMFrames !=NULL);
if (pFramesWritten !=NULL) {
*pFramesWritten=0;
}
pWAVEHDR=(MA_WAVEHDR*)Md->winmm.pWAVEHDRPlayback;
totalFramesWritten=0;
while (totalFramesWritten<frameCount) {
if (pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwUser==0) {
M3 bpf=ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
M3 framesRemainingInHeader=(pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwBufferLength/bpf)-Md->winmm.headerFramesConsumedPlayback;
M3 framesToCopy=ma_min(framesRemainingInHeader,(frameCount-totalFramesWritten));
const Mv*pSrc=ma_offset_ptr(pPCMFrames,totalFramesWritten*bpf);
Mv*pDst=ma_offset_ptr(pWAVEHDR[Md->winmm.iNextHeaderPlayback].lpData,Md->winmm.headerFramesConsumedPlayback*bpf);
MA_COPY_MEMORY(pDst,pSrc,framesToCopy*bpf);
Md->winmm.headerFramesConsumedPlayback+=framesToCopy;
totalFramesWritten+=framesToCopy;
if (Md->winmm.headerFramesConsumedPlayback==(pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwBufferLength/bpf)) {
pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwUser=1;
pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwFlags&=~MA_WHDR_DONE;
ResetEvent((HANDLE)Md->winmm.hEventPlayback);
resultMM=((MA_PFN_waveOutWrite)Md->Mc->winmm.waveOutWrite)((MA_HWAVEOUT)Md->winmm.hDevicePlayback,&pWAVEHDR[Md->winmm.iNextHeaderPlayback],sizeof(MA_WAVEHDR));
if (resultMM !=MA_MMSYSERR_NOERROR) {
 Mf=ma_result_from_MMRESULT(resultMM);
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.");
 break;
}
Md->winmm.iNextHeaderPlayback=(Md->winmm.iNextHeaderPlayback+1) % Md->playback.internalPeriods;
Md->winmm.headerFramesConsumedPlayback=0;
}
MA_ASSERT(totalFramesWritten<=frameCount);
if (totalFramesWritten==frameCount) {
break;
}
continue;
}
if (WaitForSingleObject((HANDLE)Md->winmm.hEventPlayback,INFINITE) !=WAIT_OBJECT_0) {
Mf=MA_ERROR;
break;
}
if ((pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwFlags&MA_WHDR_DONE) !=0) {
pWAVEHDR[Md->winmm.iNextHeaderPlayback].dwUser=0;
Md->winmm.headerFramesConsumedPlayback=0;
}
if (ma_device_get_state(Md) !=ma_device_state_started) {
break;
}
}
if (pFramesWritten !=NULL) {
*pFramesWritten=totalFramesWritten;
}
Mr Mf;
}
static Me ma_device_read__winmm(ma_device*Md,Mv*pPCMFrames,M3 frameCount,M3*pFramesRead)
{
Me Mf=Ms;
MA_MMRESULT resultMM;
M3 totalFramesRead;
MA_WAVEHDR*pWAVEHDR;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pPCMFrames !=NULL);
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
pWAVEHDR=(MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture;
totalFramesRead=0;
while (totalFramesRead<frameCount) {
if (pWAVEHDR[Md->winmm.iNextHeaderCapture].dwUser==0) {
M3 bpf=ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
M3 framesRemainingInHeader=(pWAVEHDR[Md->winmm.iNextHeaderCapture].dwBufferLength/bpf)-Md->winmm.headerFramesConsumedCapture;
M3 framesToCopy=ma_min(framesRemainingInHeader,(frameCount-totalFramesRead));
const Mv*pSrc=ma_offset_ptr(pWAVEHDR[Md->winmm.iNextHeaderCapture].lpData,Md->winmm.headerFramesConsumedCapture*bpf);
Mv*pDst=ma_offset_ptr(pPCMFrames,totalFramesRead*bpf);
MA_COPY_MEMORY(pDst,pSrc,framesToCopy*bpf);
Md->winmm.headerFramesConsumedCapture+=framesToCopy;
totalFramesRead+=framesToCopy;
if (Md->winmm.headerFramesConsumedCapture==(pWAVEHDR[Md->winmm.iNextHeaderCapture].dwBufferLength/bpf)) {
pWAVEHDR[Md->winmm.iNextHeaderCapture].dwUser=1;
pWAVEHDR[Md->winmm.iNextHeaderCapture].dwFlags&=~MA_WHDR_DONE;
ResetEvent((HANDLE)Md->winmm.hEventCapture);
resultMM=((MA_PFN_waveInAddBuffer)Md->Mc->winmm.waveInAddBuffer)((MA_HWAVEIN)Md->winmm.hDeviceCapture,&((MA_WAVEHDR*)Md->winmm.pWAVEHDRCapture)[Md->winmm.iNextHeaderCapture],sizeof(MA_WAVEHDR));
if (resultMM !=MA_MMSYSERR_NOERROR) {
 Mf=ma_result_from_MMRESULT(resultMM);
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.");
 break;
}
Md->winmm.iNextHeaderCapture=(Md->winmm.iNextHeaderCapture+1) % Md->capture.internalPeriods;
Md->winmm.headerFramesConsumedCapture=0;
}
MA_ASSERT(totalFramesRead<=frameCount);
if (totalFramesRead==frameCount) {
break;
}
continue;
}
if (WaitForSingleObject((HANDLE)Md->winmm.hEventCapture,INFINITE) !=WAIT_OBJECT_0) {
Mf=MA_ERROR;
break;
}
if ((pWAVEHDR[Md->winmm.iNextHeaderCapture].dwFlags&MA_WHDR_DONE) !=0) {
pWAVEHDR[Md->winmm.iNextHeaderCapture].dwUser=0;
Md->winmm.headerFramesConsumedCapture=0;
}
if (ma_device_get_state(Md) !=ma_device_state_started) {
break;
}
}
if (pFramesRead !=NULL) {
*pFramesRead=totalFramesRead;
}
Mr Mf;
}
static Me ma_context_uninit__winmm(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_winmm);
ma_dlclose(ma_context_get_log(Mc),Mc->winmm.hWinMM);
Mr Ms;
}
static Me ma_context_init__winmm(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
Mc->winmm.hWinMM = ma_dlopen(ma_context_get_log(Mc), "winmm.dll");
if (Mc->winmm.hWinMM==NULL) {
Mr MA_NO_BACKEND;
}
Mc->winmm.waveOutGetNumDevs = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutGetNumDevs");
Mc->winmm.waveOutGetDevCapsA = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutGetDevCapsA");
Mc->winmm.waveOutOpen = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutOpen");
Mc->winmm.waveOutClose = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutClose");
Mc->winmm.waveOutPrepareHeader = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutPrepareHeader");
Mc->winmm.waveOutUnprepareHeader = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutUnprepareHeader");
Mc->winmm.waveOutWrite = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutWrite");
Mc->winmm.waveOutReset = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveOutReset");
Mc->winmm.waveInGetNumDevs = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInGetNumDevs");
Mc->winmm.waveInGetDevCapsA = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInGetDevCapsA");
Mc->winmm.waveInOpen = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInOpen");
Mc->winmm.waveInClose = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInClose");
Mc->winmm.waveInPrepareHeader = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInPrepareHeader");
Mc->winmm.waveInUnprepareHeader = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInUnprepareHeader");
Mc->winmm.waveInAddBuffer = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInAddBuffer");
Mc->winmm.waveInStart = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInStart");
Mc->winmm.waveInReset = ma_dlsym(ma_context_get_log(Mc), Mc->winmm.hWinMM, "waveInReset");
pCallbacks->onContextInit=ma_context_init__winmm;
pCallbacks->onContextUninit=ma_context_uninit__winmm;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__winmm;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__winmm;
pCallbacks->onDeviceInit=ma_device_init__winmm;
pCallbacks->onDeviceUninit=ma_device_uninit__winmm;
pCallbacks->onDeviceStart=ma_device_start__winmm;
pCallbacks->onDeviceStop=ma_device_stop__winmm;
pCallbacks->onDeviceRead=ma_device_read__winmm;
pCallbacks->onDeviceWrite=ma_device_write__winmm;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#ifdef MA_HAS_ALSA
#include <poll.h>
#include <sys/eventfd.h>
#ifdef MA_NO_RUNTIME_LINKING
#if !defined(__cplusplus)
#if defined(__STRICT_ANSI__)
#if !defined(inline)
#define inline __inline__ __attribute__((always_inline))
#define MA_INLINE_DEFINED
#endif
#endif
#endif
#include <alsa/asoundlib.h>
#if defined(MA_INLINE_DEFINED)
#undef inline
#undef MA_INLINE_DEFINED
#endif
typedef snd_pcm_uframes_t ma_snd_pcm_uframes_t;
typedef snd_pcm_sframes_t ma_snd_pcm_sframes_t;
typedef snd_pcm_stream_t ma_snd_pcm_stream_t;
typedef snd_pcm_format_t ma_snd_pcm_format_t;
typedef snd_pcm_access_t ma_snd_pcm_access_t;
typedef snd_pcm_t ma_snd_pcm_t;
typedef snd_pcm_hw_params_t ma_snd_pcm_hw_params_t;
typedef snd_pcm_sw_params_t ma_snd_pcm_sw_params_t;
typedef snd_pcm_format_mask_t ma_snd_pcm_format_mask_t;
typedef snd_pcm_info_t ma_snd_pcm_info_t;
typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t;
typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t;
typedef snd_pcm_state_t ma_snd_pcm_state_t;
#define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK
#define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE
#define MA_SND_PCM_FORMAT_UNKNOWN SND_PCM_FORMAT_UNKNOWN
#define MA_SND_PCM_FORMAT_U8 SND_PCM_FORMAT_U8
#define MA_SND_PCM_FORMAT_S16_LE SND_PCM_FORMAT_S16_LE
#define MA_SND_PCM_FORMAT_S16_BE SND_PCM_FORMAT_S16_BE
#define MA_SND_PCM_FORMAT_S24_LE SND_PCM_FORMAT_S24_LE
#define MA_SND_PCM_FORMAT_S24_BE SND_PCM_FORMAT_S24_BE
#define MA_SND_PCM_FORMAT_S32_LE SND_PCM_FORMAT_S32_LE
#define MA_SND_PCM_FORMAT_S32_BE SND_PCM_FORMAT_S32_BE
#define MA_SND_PCM_FORMAT_FLOAT_LE SND_PCM_FORMAT_FLOAT_LE
#define MA_SND_PCM_FORMAT_FLOAT_BE SND_PCM_FORMAT_FLOAT_BE
#define MA_SND_PCM_FORMAT_FLOAT64_LE SND_PCM_FORMAT_FLOAT64_LE
#define MA_SND_PCM_FORMAT_FLOAT64_BE SND_PCM_FORMAT_FLOAT64_BE
#define MA_SND_PCM_FORMAT_MU_LAW SND_PCM_FORMAT_MU_LAW
#define MA_SND_PCM_FORMAT_A_LAW SND_PCM_FORMAT_A_LAW
#define MA_SND_PCM_FORMAT_S24_3LE SND_PCM_FORMAT_S24_3LE
#define MA_SND_PCM_FORMAT_S24_3BE SND_PCM_FORMAT_S24_3BE
#define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED SND_PCM_ACCESS_MMAP_INTERLEAVED
#define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED SND_PCM_ACCESS_MMAP_NONINTERLEAVED
#define MA_SND_PCM_ACCESS_MMAP_COMPLEX SND_PCM_ACCESS_MMAP_COMPLEX
#define MA_SND_PCM_ACCESS_RW_INTERLEAVED SND_PCM_ACCESS_RW_INTERLEAVED
#define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED SND_PCM_ACCESS_RW_NONINTERLEAVED
#define MA_SND_CHMAP_UNKNOWN SND_CHMAP_UNKNOWN
#define MA_SND_CHMAP_NA SND_CHMAP_NA
#define MA_SND_CHMAP_MONO SND_CHMAP_MONO
#define MA_SND_CHMAP_FL SND_CHMAP_FL
#define MA_SND_CHMAP_FR SND_CHMAP_FR
#define MA_SND_CHMAP_RL SND_CHMAP_RL
#define MA_SND_CHMAP_RR SND_CHMAP_RR
#define MA_SND_CHMAP_FC SND_CHMAP_FC
#define MA_SND_CHMAP_LFE SND_CHMAP_LFE
#define MA_SND_CHMAP_SL SND_CHMAP_SL
#define MA_SND_CHMAP_SR SND_CHMAP_SR
#define MA_SND_CHMAP_RC SND_CHMAP_RC
#define MA_SND_CHMAP_FLC SND_CHMAP_FLC
#define MA_SND_CHMAP_FRC SND_CHMAP_FRC
#define MA_SND_CHMAP_RLC SND_CHMAP_RLC
#define MA_SND_CHMAP_RRC SND_CHMAP_RRC
#define MA_SND_CHMAP_FLW SND_CHMAP_FLW
#define MA_SND_CHMAP_FRW SND_CHMAP_FRW
#define MA_SND_CHMAP_FLH SND_CHMAP_FLH
#define MA_SND_CHMAP_FCH SND_CHMAP_FCH
#define MA_SND_CHMAP_FRH SND_CHMAP_FRH
#define MA_SND_CHMAP_TC SND_CHMAP_TC
#define MA_SND_CHMAP_TFL SND_CHMAP_TFL
#define MA_SND_CHMAP_TFR SND_CHMAP_TFR
#define MA_SND_CHMAP_TFC SND_CHMAP_TFC
#define MA_SND_CHMAP_TRL SND_CHMAP_TRL
#define MA_SND_CHMAP_TRR SND_CHMAP_TRR
#define MA_SND_CHMAP_TRC SND_CHMAP_TRC
#define MA_SND_CHMAP_TFLC SND_CHMAP_TFLC
#define MA_SND_CHMAP_TFRC SND_CHMAP_TFRC
#define MA_SND_CHMAP_TSL SND_CHMAP_TSL
#define MA_SND_CHMAP_TSR SND_CHMAP_TSR
#define MA_SND_CHMAP_LLFE SND_CHMAP_LLFE
#define MA_SND_CHMAP_RLFE SND_CHMAP_RLFE
#define MA_SND_CHMAP_BC SND_CHMAP_BC
#define MA_SND_CHMAP_BLC SND_CHMAP_BLC
#define MA_SND_CHMAP_BRC SND_CHMAP_BRC
#define MA_SND_PCM_NO_AUTO_RESAMPLE SND_PCM_NO_AUTO_RESAMPLE
#define MA_SND_PCM_NO_AUTO_CHANNELS SND_PCM_NO_AUTO_CHANNELS
#define MA_SND_PCM_NO_AUTO_FORMAT SND_PCM_NO_AUTO_FORMAT
#else
#include <errno.h>
typedef unsigned long ma_snd_pcm_uframes_t;
typedef long ma_snd_pcm_sframes_t;
typedef int ma_snd_pcm_stream_t;
typedef int ma_snd_pcm_format_t;
typedef int ma_snd_pcm_access_t;
typedef int ma_snd_pcm_state_t;
typedef struct ma_snd_pcm_t ma_snd_pcm_t;
typedef struct ma_snd_pcm_hw_params_t ma_snd_pcm_hw_params_t;
typedef struct ma_snd_pcm_sw_params_t ma_snd_pcm_sw_params_t;
typedef struct ma_snd_pcm_format_mask_t ma_snd_pcm_format_mask_t;
typedef struct ma_snd_pcm_info_t ma_snd_pcm_info_t;
typedef struct
{
Mv*addr;
unsigned int first;
unsigned int step;
} ma_snd_pcm_channel_area_t;
typedef struct
{
unsigned int Mh;
unsigned int pos[1];
} ma_snd_pcm_chmap_t;
#define MA_SND_PCM_STATE_OPEN 0
#define MA_SND_PCM_STATE_SETUP 1
#define MA_SND_PCM_STATE_PREPARED 2
#define MA_SND_PCM_STATE_RUNNING 3
#define MA_SND_PCM_STATE_XRUN 4
#define MA_SND_PCM_STATE_DRAINING 5
#define MA_SND_PCM_STATE_PAUSED 6
#define MA_SND_PCM_STATE_SUSPENDED 7
#define MA_SND_PCM_STATE_DISCONNECTED 8
#define MA_SND_PCM_STREAM_PLAYBACK 0
#define MA_SND_PCM_STREAM_CAPTURE 1
#define MA_SND_PCM_FORMAT_UNKNOWN -1
#define MA_SND_PCM_FORMAT_U8 1
#define MA_SND_PCM_FORMAT_S16_LE 2
#define MA_SND_PCM_FORMAT_S16_BE 3
#define MA_SND_PCM_FORMAT_S24_LE 6
#define MA_SND_PCM_FORMAT_S24_BE 7
#define MA_SND_PCM_FORMAT_S32_LE 10
#define MA_SND_PCM_FORMAT_S32_BE 11
#define MA_SND_PCM_FORMAT_FLOAT_LE 14
#define MA_SND_PCM_FORMAT_FLOAT_BE 15
#define MA_SND_PCM_FORMAT_FLOAT64_LE 16
#define MA_SND_PCM_FORMAT_FLOAT64_BE 17
#define MA_SND_PCM_FORMAT_MU_LAW 20
#define MA_SND_PCM_FORMAT_A_LAW 21
#define MA_SND_PCM_FORMAT_S24_3LE 32
#define MA_SND_PCM_FORMAT_S24_3BE 33
#define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED 0
#define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED 1
#define MA_SND_PCM_ACCESS_MMAP_COMPLEX 2
#define MA_SND_PCM_ACCESS_RW_INTERLEAVED 3
#define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED 4
#define MA_SND_CHMAP_UNKNOWN 0
#define MA_SND_CHMAP_NA 1
#define MA_SND_CHMAP_MONO 2
#define MA_SND_CHMAP_FL 3
#define MA_SND_CHMAP_FR 4
#define MA_SND_CHMAP_RL 5
#define MA_SND_CHMAP_RR 6
#define MA_SND_CHMAP_FC 7
#define MA_SND_CHMAP_LFE 8
#define MA_SND_CHMAP_SL 9
#define MA_SND_CHMAP_SR 10
#define MA_SND_CHMAP_RC 11
#define MA_SND_CHMAP_FLC 12
#define MA_SND_CHMAP_FRC 13
#define MA_SND_CHMAP_RLC 14
#define MA_SND_CHMAP_RRC 15
#define MA_SND_CHMAP_FLW 16
#define MA_SND_CHMAP_FRW 17
#define MA_SND_CHMAP_FLH 18
#define MA_SND_CHMAP_FCH 19
#define MA_SND_CHMAP_FRH 20
#define MA_SND_CHMAP_TC 21
#define MA_SND_CHMAP_TFL 22
#define MA_SND_CHMAP_TFR 23
#define MA_SND_CHMAP_TFC 24
#define MA_SND_CHMAP_TRL 25
#define MA_SND_CHMAP_TRR 26
#define MA_SND_CHMAP_TRC 27
#define MA_SND_CHMAP_TFLC 28
#define MA_SND_CHMAP_TFRC 29
#define MA_SND_CHMAP_TSL 30
#define MA_SND_CHMAP_TSR 31
#define MA_SND_CHMAP_LLFE 32
#define MA_SND_CHMAP_RLFE 33
#define MA_SND_CHMAP_BC 34
#define MA_SND_CHMAP_BLC 35
#define MA_SND_CHMAP_BRC 36
#define MA_SND_PCM_NO_AUTO_RESAMPLE 0x00010000
#define MA_SND_PCM_NO_AUTO_CHANNELS 0x00020000
#define MA_SND_PCM_NO_AUTO_FORMAT 0x00040000
#endif
typedef int (*ma_snd_pcm_open_proc) (ma_snd_pcm_t**pcm,const char*name,ma_snd_pcm_stream_t stream,int mode);
typedef int (*ma_snd_pcm_close_proc) (ma_snd_pcm_t*pcm);
typedef size_t (*ma_snd_pcm_hw_params_sizeof_proc) (Mv);
typedef int (*ma_snd_pcm_hw_params_any_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params);
typedef int (*ma_snd_pcm_hw_params_set_format_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,ma_snd_pcm_format_t val);
typedef int (*ma_snd_pcm_hw_params_set_format_first_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,ma_snd_pcm_format_t*format);
typedef Mv (*ma_snd_pcm_hw_params_get_format_mask_proc) (ma_snd_pcm_hw_params_t*params,ma_snd_pcm_format_mask_t*mask);
typedef int (*ma_snd_pcm_hw_params_set_channels_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int val);
typedef int (*ma_snd_pcm_hw_params_set_channels_near_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int*val);
typedef int (*ma_snd_pcm_hw_params_set_channels_minmax_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int*minimum,unsigned int*maximum);
typedef int (*ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int val);
typedef int (*ma_snd_pcm_hw_params_set_rate_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int val,int dir);
typedef int (*ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int*val,int*dir);
typedef int (*ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,ma_snd_pcm_uframes_t*val);
typedef int (*ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int*val,int*dir);
typedef int (*ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,ma_snd_pcm_access_t _access);
typedef int (*ma_snd_pcm_hw_params_get_format_proc) (const ma_snd_pcm_hw_params_t*params,ma_snd_pcm_format_t*format);
typedef int (*ma_snd_pcm_hw_params_get_channels_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*val);
typedef int (*ma_snd_pcm_hw_params_get_channels_min_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*val);
typedef int (*ma_snd_pcm_hw_params_get_channels_max_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*val);
typedef int (*ma_snd_pcm_hw_params_get_rate_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*rate,int*dir);
typedef int (*ma_snd_pcm_hw_params_get_rate_min_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*rate,int*dir);
typedef int (*ma_snd_pcm_hw_params_get_rate_max_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*rate,int*dir);
typedef int (*ma_snd_pcm_hw_params_get_buffer_size_proc) (const ma_snd_pcm_hw_params_t*params,ma_snd_pcm_uframes_t*val);
typedef int (*ma_snd_pcm_hw_params_get_periods_proc) (const ma_snd_pcm_hw_params_t*params,unsigned int*val,int*dir);
typedef int (*ma_snd_pcm_hw_params_get_access_proc) (const ma_snd_pcm_hw_params_t*params,ma_snd_pcm_access_t*_access);
typedef int (*ma_snd_pcm_hw_params_test_format_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,ma_snd_pcm_format_t val);
typedef int (*ma_snd_pcm_hw_params_test_channels_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int val);
typedef int (*ma_snd_pcm_hw_params_test_rate_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params,unsigned int val,int dir);
typedef int (*ma_snd_pcm_hw_params_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_hw_params_t*params);
typedef size_t (*ma_snd_pcm_sw_params_sizeof_proc) (Mv);
typedef int (*ma_snd_pcm_sw_params_current_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_sw_params_t*params);
typedef int (*ma_snd_pcm_sw_params_get_boundary_proc) (const ma_snd_pcm_sw_params_t*params,ma_snd_pcm_uframes_t*val);
typedef int (*ma_snd_pcm_sw_params_set_avail_min_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_sw_params_t*params,ma_snd_pcm_uframes_t val);
typedef int (*ma_snd_pcm_sw_params_set_start_threshold_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_sw_params_t*params,ma_snd_pcm_uframes_t val);
typedef int (*ma_snd_pcm_sw_params_set_stop_threshold_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_sw_params_t*params,ma_snd_pcm_uframes_t val);
typedef int (*ma_snd_pcm_sw_params_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_sw_params_t*params);
typedef size_t (*ma_snd_pcm_format_mask_sizeof_proc) (Mv);
typedef int (*ma_snd_pcm_format_mask_test_proc) (const ma_snd_pcm_format_mask_t*mask,ma_snd_pcm_format_t val);
typedef ma_snd_pcm_chmap_t*(*ma_snd_pcm_get_chmap_proc) (ma_snd_pcm_t*pcm);
typedef ma_snd_pcm_state_t (*ma_snd_pcm_state_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_prepare_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_start_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_drop_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_drain_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_reset_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_device_name_hint_proc) (int card,const char*iface,Mv***hints);
typedef char*(*ma_snd_device_name_get_hint_proc) (const Mv*hint,const char*id);
typedef int (*ma_snd_card_get_index_proc) (const char*name);
typedef int (*ma_snd_device_name_free_hint_proc) (Mv**hints);
typedef int (*ma_snd_pcm_mmap_begin_proc) (ma_snd_pcm_t*pcm,const ma_snd_pcm_channel_area_t**areas,ma_snd_pcm_uframes_t*offset,ma_snd_pcm_uframes_t*frames);
typedef ma_snd_pcm_sframes_t (*ma_snd_pcm_mmap_commit_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_uframes_t offset,ma_snd_pcm_uframes_t frames);
typedef int (*ma_snd_pcm_recover_proc) (ma_snd_pcm_t*pcm,int err,int silent);
typedef ma_snd_pcm_sframes_t (*ma_snd_pcm_readi_proc) (ma_snd_pcm_t*pcm,Mv*buffer,ma_snd_pcm_uframes_t size);
typedef ma_snd_pcm_sframes_t (*ma_snd_pcm_writei_proc) (ma_snd_pcm_t*pcm,const Mv*buffer,ma_snd_pcm_uframes_t size);
typedef ma_snd_pcm_sframes_t (*ma_snd_pcm_avail_proc) (ma_snd_pcm_t*pcm);
typedef ma_snd_pcm_sframes_t (*ma_snd_pcm_avail_update_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_wait_proc) (ma_snd_pcm_t*pcm,int timeout);
typedef int (*ma_snd_pcm_nonblock_proc) (ma_snd_pcm_t*pcm,int nonblock);
typedef int (*ma_snd_pcm_info_proc) (ma_snd_pcm_t*pcm,ma_snd_pcm_info_t*info);
typedef size_t (*ma_snd_pcm_info_sizeof_proc) (Mv);
typedef const char*(*ma_snd_pcm_info_get_name_proc) (const ma_snd_pcm_info_t*info);
typedef int (*ma_snd_pcm_poll_descriptors_proc) (ma_snd_pcm_t*pcm,struct pollfd*pfds,unsigned int space);
typedef int (*ma_snd_pcm_poll_descriptors_count_proc) (ma_snd_pcm_t*pcm);
typedef int (*ma_snd_pcm_poll_descriptors_revents_proc) (ma_snd_pcm_t*pcm,struct pollfd*pfds,unsigned int nfds,unsigned short*revents);
typedef int (*ma_snd_config_update_free_global_proc) (Mv);
static const char*g_maCommonDeviceNamesALSA[]={
"default","null","pulse","jack"
};
static const char*g_maBlacklistedPlaybackDeviceNamesALSA[]={
""
};
static const char*g_maBlacklistedCaptureDeviceNamesALSA[]={
""
};
static ma_snd_pcm_format_t ma_convert_ma_format_to_alsa_format(ma_format format)
{
ma_snd_pcm_format_t ALSAFormats[]={
MA_SND_PCM_FORMAT_UNKNOWN,MA_SND_PCM_FORMAT_U8,MA_SND_PCM_FORMAT_S16_LE,MA_SND_PCM_FORMAT_S24_3LE,MA_SND_PCM_FORMAT_S32_LE,MA_SND_PCM_FORMAT_FLOAT_LE
};
if (ma_is_big_endian()) {
ALSAFormats[0]=MA_SND_PCM_FORMAT_UNKNOWN;
ALSAFormats[1]=MA_SND_PCM_FORMAT_U8;
ALSAFormats[2]=MA_SND_PCM_FORMAT_S16_BE;
ALSAFormats[3]=MA_SND_PCM_FORMAT_S24_3BE;
ALSAFormats[4]=MA_SND_PCM_FORMAT_S32_BE;
ALSAFormats[5]=MA_SND_PCM_FORMAT_FLOAT_BE;
}
Mr ALSAFormats[format];
}
static ma_format ma_format_from_alsa(ma_snd_pcm_format_t formatALSA)
{
if (ma_is_little_endian()) {
switch (formatALSA) {
case MA_SND_PCM_FORMAT_S16_LE:Mr ma_format_s16;
case MA_SND_PCM_FORMAT_S24_3LE:Mr ma_format_s24;
case MA_SND_PCM_FORMAT_S32_LE:Mr ma_format_s32;
case MA_SND_PCM_FORMAT_FLOAT_LE:Mr ma_format_f32;
default:break;
}
} else {
switch (formatALSA) {
case MA_SND_PCM_FORMAT_S16_BE:Mr ma_format_s16;
case MA_SND_PCM_FORMAT_S24_3BE:Mr ma_format_s24;
case MA_SND_PCM_FORMAT_S32_BE:Mr ma_format_s32;
case MA_SND_PCM_FORMAT_FLOAT_BE:Mr ma_format_f32;
default:break;
}
}
switch (formatALSA) {
case MA_SND_PCM_FORMAT_U8:Mr ma_format_u8;
default:Mr ma_format_unknown;
}
}
static ma_channel ma_convert_alsa_channel_position_to_ma_channel(unsigned int alsaChannelPos)
{
switch (alsaChannelPos)
{
case MA_SND_CHMAP_MONO:Mr MA_CHANNEL_MONO;
case MA_SND_CHMAP_FL:Mr MA_CHANNEL_FRONT_LEFT;
case MA_SND_CHMAP_FR:Mr MA_CHANNEL_FRONT_RIGHT;
case MA_SND_CHMAP_RL:Mr MA_CHANNEL_BACK_LEFT;
case MA_SND_CHMAP_RR:Mr MA_CHANNEL_BACK_RIGHT;
case MA_SND_CHMAP_FC:Mr MA_CHANNEL_FRONT_CENTER;
case MA_SND_CHMAP_LFE:Mr MA_CHANNEL_LFE;
case MA_SND_CHMAP_SL:Mr MA_CHANNEL_SIDE_LEFT;
case MA_SND_CHMAP_SR:Mr MA_CHANNEL_SIDE_RIGHT;
case MA_SND_CHMAP_RC:Mr MA_CHANNEL_BACK_CENTER;
case MA_SND_CHMAP_FLC:Mr MA_CHANNEL_FRONT_LEFT_CENTER;
case MA_SND_CHMAP_FRC:Mr MA_CHANNEL_FRONT_RIGHT_CENTER;
case MA_SND_CHMAP_RLC:Mr 0;
case MA_SND_CHMAP_RRC:Mr 0;
case MA_SND_CHMAP_FLW:Mr 0;
case MA_SND_CHMAP_FRW:Mr 0;
case MA_SND_CHMAP_FLH:Mr 0;
case MA_SND_CHMAP_FCH:Mr 0;
case MA_SND_CHMAP_FRH:Mr 0;
case MA_SND_CHMAP_TC:Mr MA_CHANNEL_TOP_CENTER;
case MA_SND_CHMAP_TFL:Mr MA_CHANNEL_TOP_FRONT_LEFT;
case MA_SND_CHMAP_TFR:Mr MA_CHANNEL_TOP_FRONT_RIGHT;
case MA_SND_CHMAP_TFC:Mr MA_CHANNEL_TOP_FRONT_CENTER;
case MA_SND_CHMAP_TRL:Mr MA_CHANNEL_TOP_BACK_LEFT;
case MA_SND_CHMAP_TRR:Mr MA_CHANNEL_TOP_BACK_RIGHT;
case MA_SND_CHMAP_TRC:Mr MA_CHANNEL_TOP_BACK_CENTER;
default:break;
}
Mr 0;
}
static ma_bool32 ma_is_common_device_name__alsa(const char*name)
{
size_t iName;
for (iName=0; iName<ma_countof(g_maCommonDeviceNamesALSA);++iName) {
if (ma_strcmp(name,g_maCommonDeviceNamesALSA[iName])==0) {
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
static ma_bool32 ma_is_playback_device_blacklisted__alsa(const char*name)
{
size_t iName;
for (iName=0; iName<ma_countof(g_maBlacklistedPlaybackDeviceNamesALSA);++iName) {
if (ma_strcmp(name,g_maBlacklistedPlaybackDeviceNamesALSA[iName])==0) {
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
static ma_bool32 ma_is_capture_device_blacklisted__alsa(const char*name)
{
size_t iName;
for (iName=0; iName<ma_countof(g_maBlacklistedCaptureDeviceNamesALSA);++iName) {
if (ma_strcmp(name,g_maBlacklistedCaptureDeviceNamesALSA[iName])==0) {
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
static ma_bool32 ma_is_device_blacklisted__alsa(ma_device_type deviceType,const char*name)
{
if (deviceType==Mt) {
Mr ma_is_playback_device_blacklisted__alsa(name);
} else {
Mr ma_is_capture_device_blacklisted__alsa(name);
}
}
static const char*ma_find_char(const char*str,char c,int*index)
{
int i=0;
for (;;) {
if (str[i]=='\0') {
if (index)*index=-1;
Mr NULL;
}
if (str[i]==c) {
if (index)*index=i;
Mr str+i;
}
i+=1;
}
if (index)*index=-1;
Mr NULL;
}
static ma_bool32 ma_is_device_name_in_hw_format__alsa(const char*hwid)
{
int commaPos;
const char*dev;
int i;
if (hwid==NULL) {
Mr MA_FALSE;
}
if (hwid[0] !='h'||hwid[1] !='w'||hwid[2] !=':') {
Mr MA_FALSE;
}
hwid+=3;
dev=ma_find_char(hwid,',',&commaPos);
if (dev==NULL) {
Mr MA_FALSE;
} else {
dev+=1;
}
for (i=0; i<commaPos;++i) {
if (hwid[i]<'0'||hwid[i]>'9') {
Mr MA_FALSE;
}
}
i=0;
while (dev[i] !='\0') {
if (dev[i]<'0'||dev[i]>'9') {
Mr MA_FALSE;
}
i+=1;
}
Mr MA_TRUE;
}
static int ma_convert_device_name_to_hw_format__alsa(ma_context*Mc,char*dst,size_t dstSize,const char*src)
{
int colonPos;
int commaPos;
char card[256];
const char*dev;
int cardIndex;
if (dst==NULL) {
Mr-1;
}
if (dstSize<7) {
Mr-1;
}
*dst='\0';
if (src==NULL) {
Mr-1;
}
if (ma_is_device_name_in_hw_format__alsa(src)) {
Mr ma_strcpy_s(dst,dstSize,src);
}
src=ma_find_char(src,':',&colonPos);
if (src==NULL) {
Mr-1;
}
dev=ma_find_char(src,',',&commaPos);
if (dev==NULL) {
dev = "0";
ma_strncpy_s(card,sizeof(card),src+6,(size_t)-1);
} else {
dev=dev+5;
ma_strncpy_s(card,sizeof(card),src+6,commaPos-6);
}
cardIndex=((ma_snd_card_get_index_proc)Mc->alsa.snd_card_get_index)(card);
if (cardIndex<0) {
Mr-2;
}
dst[0]='h'; dst[1]='w'; dst[2]=':';
if (ma_itoa_s(cardIndex,dst+3,dstSize-3,10) !=0) {
Mr-3;
}
if (ma_strcat_s(dst, dstSize, ",") != 0) {
Mr-3;
}
if (ma_strcat_s(dst,dstSize,dev) !=0) {
Mr-3;
}
Mr 0;
}
static ma_bool32 ma_does_id_exist_in_list__alsa(ma_device_id*pUniqueIDs,M3 count,const char*pHWID)
{
M3 i;
MA_ASSERT(pHWID !=NULL);
for (i=0; i<count;++i) {
if (ma_strcmp(pUniqueIDs[i].alsa,pHWID)==0) {
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
static Me ma_context_open_pcm__alsa(ma_context*Mc,ma_share_mode shareMode,ma_device_type deviceType,const ma_device_id*pDeviceID,int openMode,ma_snd_pcm_t**ppPCM)
{
ma_snd_pcm_t*pPCM;
ma_snd_pcm_stream_t stream;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppPCM !=NULL);
*ppPCM=NULL;
pPCM=NULL;
stream=(deviceType==Mt)?MA_SND_PCM_STREAM_PLAYBACK:MA_SND_PCM_STREAM_CAPTURE;
if (pDeviceID==NULL) {
ma_bool32 isDeviceOpen;
size_t i;
const char*defaultDeviceNames[]={
"default",NULL,NULL,NULL,NULL,NULL,NULL
};
if (shareMode==ma_share_mode_exclusive) {
defaultDeviceNames[1] = "hw";
defaultDeviceNames[2] = "hw:0";
defaultDeviceNames[3] = "hw:0,0";
} else {
if (deviceType==Mt) {
defaultDeviceNames[1] = "dmix";
defaultDeviceNames[2] = "dmix:0";
defaultDeviceNames[3] = "dmix:0,0";
} else {
defaultDeviceNames[1] = "dsnoop";
defaultDeviceNames[2] = "dsnoop:0";
defaultDeviceNames[3] = "dsnoop:0,0";
}
defaultDeviceNames[4] = "hw";
defaultDeviceNames[5] = "hw:0";
defaultDeviceNames[6] = "hw:0,0";
}
isDeviceOpen=MA_FALSE;
for (i=0; i<ma_countof(defaultDeviceNames);++i) {
if (defaultDeviceNames[i] !=NULL&&defaultDeviceNames[i][0] !='\0') {
if (((ma_snd_pcm_open_proc)Mc->alsa.snd_pcm_open)(&pPCM,defaultDeviceNames[i],stream,openMode)==0) {
 isDeviceOpen=MA_TRUE;
 break;
}
}
}
if (!isDeviceOpen) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
} else {
ma_device_id deviceID=*pDeviceID;
int resultALSA=-ENODEV;
if (deviceID.alsa[0] !=':') {
resultALSA=((ma_snd_pcm_open_proc)Mc->alsa.snd_pcm_open)(&pPCM,deviceID.alsa,stream,openMode);
} else {
char hwid[256];
if (deviceID.alsa[1]=='\0') {
deviceID.alsa[0]='\0';
}
if (shareMode==ma_share_mode_shared) {
if (deviceType==Mt) {
 ma_strcpy_s(hwid, sizeof(hwid), "dmix");
} else {
 ma_strcpy_s(hwid, sizeof(hwid), "dsnoop");
}
if (ma_strcat_s(hwid,sizeof(hwid),deviceID.alsa)==0) {
 resultALSA=((ma_snd_pcm_open_proc)Mc->alsa.snd_pcm_open)(&pPCM,hwid,stream,openMode);
}
}
if (resultALSA !=0) {
ma_strcpy_s(hwid, sizeof(hwid), "hw");
if (ma_strcat_s(hwid,sizeof(hwid),deviceID.alsa)==0) {
 resultALSA=((ma_snd_pcm_open_proc)Mc->alsa.snd_pcm_open)(&pPCM,hwid,stream,openMode);
}
}
}
if (resultALSA<0) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.");
Mr ma_result_from_errno(-resultALSA);
}
}
*ppPCM=pPCM;
Mr Ms;
}
static Me ma_context_enumerate_devices__alsa(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
int resultALSA;
ma_bool32 cbResult=MA_TRUE;
char**ppDeviceHints;
ma_device_id*pUniqueIDs=NULL;
M3 uniqueIDCount=0;
char**ppNextDeviceHint;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
ma_mutex_lock(&Mc->alsa.internalDeviceEnumLock);
resultALSA = ((ma_snd_device_name_hint_proc)Mc->alsa.snd_device_name_hint)(-1, "pcm", (Mv***)&ppDeviceHints);
if (resultALSA<0) {
ma_mutex_unlock(&Mc->alsa.internalDeviceEnumLock);
Mr ma_result_from_errno(-resultALSA);
}
ppNextDeviceHint=ppDeviceHints;
while (*ppNextDeviceHint !=NULL) {
char* NAME = ((ma_snd_device_name_get_hint_proc)Mc->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
char* DESC = ((ma_snd_device_name_get_hint_proc)Mc->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
char* IOID = ((ma_snd_device_name_get_hint_proc)Mc->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
ma_device_type deviceType=Mt;
ma_bool32 stopEnumeration=MA_FALSE;
char hwid[sizeof(pUniqueIDs->alsa)];
ma_device_info deviceInfo;
if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) {
deviceType=Mt;
}
if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) {
deviceType=ma_device_type_capture;
}
if (NAME !=NULL) {
if (Mc->alsa.useVerboseDeviceEnumeration) {
ma_strncpy_s(hwid,sizeof(hwid),NAME,(size_t)-1);
} else {
if (ma_convert_device_name_to_hw_format__alsa(Mc,hwid,sizeof(hwid),NAME)==0) {
 char*dst=hwid;
 char*src=hwid+2;
 while ((*dst++=*src++));
} else {
 ma_strncpy_s(hwid,sizeof(hwid),NAME,(size_t)-1);
}
if (ma_does_id_exist_in_list__alsa(pUniqueIDs,uniqueIDCount,hwid)) {
 goto next_device;
} else {
 size_t newCapacity=sizeof(*pUniqueIDs)*(uniqueIDCount+1);
 ma_device_id*pNewUniqueIDs=(ma_device_id*)ma_realloc(pUniqueIDs,newCapacity,&Mc->allocationCallbacks);
 if (pNewUniqueIDs==NULL) {
 goto next_device;
 }
 pUniqueIDs=pNewUniqueIDs;
 MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa,hwid,sizeof(hwid));
 uniqueIDCount+=1;
}
}
} else {
MA_ZERO_MEMORY(hwid,sizeof(hwid));
}
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.id.alsa,sizeof(deviceInfo.id.alsa),hwid,(size_t)-1);
if (ma_strcmp(deviceInfo.id.alsa, "default") == 0) {
deviceInfo.isDefault=MA_TRUE;
}
if (DESC !=NULL) {
int lfPos;
const char*line2=ma_find_char(DESC,'\n',&lfPos);
if (line2 !=NULL) {
line2+=1;
if (Mc->alsa.useVerboseDeviceEnumeration) {
 ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),DESC,lfPos);
 ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " (");
 ma_strcat_s (deviceInfo.name,sizeof(deviceInfo.name),line2);
 ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")");
} else {
 ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),DESC,lfPos);
}
} else {
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),DESC,(size_t)-1);
}
}
if (!ma_is_device_blacklisted__alsa(deviceType,NAME)) {
cbResult=callback(Mc,deviceType,&deviceInfo,pUserData);
}
if (cbResult) {
if (ma_is_common_device_name__alsa(NAME)||IOID==NULL) {
if (deviceType==Mt) {
 if (!ma_is_capture_device_blacklisted__alsa(NAME)) {
 cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
 }
} else {
 if (!ma_is_playback_device_blacklisted__alsa(NAME)) {
 cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
 }
}
}
}
if (cbResult==MA_FALSE) {
stopEnumeration=MA_TRUE;
}
next_device:
free(NAME);
free(DESC);
free(IOID);
ppNextDeviceHint+=1;
if (stopEnumeration) {
break;
}
}
ma_free(pUniqueIDs,&Mc->allocationCallbacks);
((ma_snd_device_name_free_hint_proc)Mc->alsa.snd_device_name_free_hint)((Mv**)ppDeviceHints);
ma_mutex_unlock(&Mc->alsa.internalDeviceEnumLock);
Mr Ms;
}
typedef struct
{
ma_device_type deviceType;
const ma_device_id*pDeviceID;
ma_share_mode shareMode;
ma_device_info*pDeviceInfo;
ma_bool32 foundDevice;
} ma_context_get_device_info_enum_callback_data__alsa;
static ma_bool32 ma_context_get_device_info_enum_callback__alsa(ma_context*Mc,ma_device_type deviceType,const ma_device_info*pDeviceInfo,Mv*pUserData)
{
ma_context_get_device_info_enum_callback_data__alsa*pData=(ma_context_get_device_info_enum_callback_data__alsa*)pUserData;
MA_ASSERT(pData !=NULL);
(Mv)Mc;
if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
ma_strncpy_s(pData->pDeviceInfo->name,sizeof(pData->pDeviceInfo->name),pDeviceInfo->name,(size_t)-1);
pData->foundDevice=MA_TRUE;
} else {
if (pData->deviceType==deviceType&&(pData->pDeviceID !=NULL&&ma_strcmp(pData->pDeviceID->alsa,pDeviceInfo->id.alsa)==0)) {
ma_strncpy_s(pData->pDeviceInfo->name,sizeof(pData->pDeviceInfo->name),pDeviceInfo->name,(size_t)-1);
pData->foundDevice=MA_TRUE;
}
}
Mr !pData->foundDevice;
}
static Mv ma_context_test_rate_and_add_native_data_format__alsa(ma_context*Mc,ma_snd_pcm_t*pPCM,ma_snd_pcm_hw_params_t*pHWParams,ma_format format,M3 Mh,M3 sampleRate,M3 flags,ma_device_info*pDeviceInfo)
{
MA_ASSERT(pPCM !=NULL);
MA_ASSERT(pHWParams !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
if (pDeviceInfo->nativeDataFormatCount<ma_countof(pDeviceInfo->nativeDataFormats)&&((ma_snd_pcm_hw_params_test_rate_proc)Mc->alsa.snd_pcm_hw_params_test_rate)(pPCM,pHWParams,sampleRate,0)==0) {
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=format;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=Mh;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=sampleRate;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=flags;
pDeviceInfo->nativeDataFormatCount+=1;
}
}
static Mv ma_context_iterate_rates_and_add_native_data_format__alsa(ma_context*Mc,ma_snd_pcm_t*pPCM,ma_snd_pcm_hw_params_t*pHWParams,ma_format format,M3 Mh,M3 flags,ma_device_info*pDeviceInfo)
{
M3 iSampleRate;
unsigned int minSampleRate;
unsigned int maxSampleRate;
int sampleRateDir;
((ma_snd_pcm_hw_params_get_rate_min_proc)Mc->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams,&minSampleRate,&sampleRateDir);
((ma_snd_pcm_hw_params_get_rate_max_proc)Mc->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams,&maxSampleRate,&sampleRateDir);
minSampleRate=ma_clamp(minSampleRate,(unsigned int)ma_standard_sample_rate_min,(unsigned int)ma_standard_sample_rate_max);
maxSampleRate=ma_clamp(maxSampleRate,(unsigned int)ma_standard_sample_rate_min,(unsigned int)ma_standard_sample_rate_max);
for (iSampleRate=0; iSampleRate<ma_countof(g_maStandardSampleRatePriorities); iSampleRate+=1) {
M3 standardSampleRate=g_maStandardSampleRatePriorities[iSampleRate];
if (standardSampleRate>=minSampleRate&&standardSampleRate<=maxSampleRate) {
ma_context_test_rate_and_add_native_data_format__alsa(Mc,pPCM,pHWParams,format,Mh,standardSampleRate,flags,pDeviceInfo);
}
}
if (!ma_is_standard_sample_rate(minSampleRate)) {
ma_context_test_rate_and_add_native_data_format__alsa(Mc,pPCM,pHWParams,format,Mh,minSampleRate,flags,pDeviceInfo);
}
if (!ma_is_standard_sample_rate(maxSampleRate)&&maxSampleRate !=minSampleRate) {
ma_context_test_rate_and_add_native_data_format__alsa(Mc,pPCM,pHWParams,format,Mh,maxSampleRate,flags,pDeviceInfo);
}
}
static Me ma_context_get_device_info__alsa(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
ma_context_get_device_info_enum_callback_data__alsa data;
Me Mf;
int resultALSA;
ma_snd_pcm_t*pPCM;
ma_snd_pcm_hw_params_t*pHWParams;
M3 iFormat;
M3 iChannel;
MA_ASSERT(Mc !=NULL);
data.deviceType=deviceType;
data.pDeviceID=pDeviceID;
data.pDeviceInfo=pDeviceInfo;
data.foundDevice=MA_FALSE;
Mf=ma_context_enumerate_devices__alsa(Mc,ma_context_get_device_info_enum_callback__alsa,&data);
if (Mf !=Ms) {
Mr Mf;
}
if (!data.foundDevice) {
Mr MA_NO_DEVICE;
}
if (ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
pDeviceInfo->isDefault=MA_TRUE;
}
Mf=ma_context_open_pcm__alsa(Mc,ma_share_mode_shared,deviceType,pDeviceID,0,&pPCM);
if (Mf !=Ms) {
Mr Mf;
}
pHWParams=(ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)Mc->alsa.snd_pcm_hw_params_sizeof)(),&Mc->allocationCallbacks);
if (pHWParams==NULL) {
((ma_snd_pcm_close_proc)Mc->alsa.snd_pcm_close)(pPCM);
Mr MA_OUT_OF_MEMORY;
}
resultALSA=((ma_snd_pcm_hw_params_any_proc)Mc->alsa.snd_pcm_hw_params_any)(pPCM,pHWParams);
if (resultALSA<0) {
ma_free(pHWParams,&Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Mc->alsa.snd_pcm_close)(pPCM);
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.");
Mr ma_result_from_errno(-resultALSA);
}
for (iFormat=0; iFormat<ma_countof(g_maFormatPriorities); iFormat+=1) {
ma_format format=g_maFormatPriorities[iFormat];
((ma_snd_pcm_hw_params_any_proc)Mc->alsa.snd_pcm_hw_params_any)(pPCM,pHWParams);
if (((ma_snd_pcm_hw_params_test_format_proc)Mc->alsa.snd_pcm_hw_params_test_format)(pPCM,pHWParams,ma_convert_ma_format_to_alsa_format(format))==0) {
unsigned int minChannels;
unsigned int maxChannels;
((ma_snd_pcm_hw_params_set_format_proc)Mc->alsa.snd_pcm_hw_params_set_format)(pPCM,pHWParams,ma_convert_ma_format_to_alsa_format(format));
((ma_snd_pcm_hw_params_get_channels_min_proc)Mc->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams,&minChannels);
((ma_snd_pcm_hw_params_get_channels_max_proc)Mc->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams,&maxChannels);
if (minChannels>MA_MAX_CHANNELS) {
continue;
}
if (maxChannels<MA_MIN_CHANNELS) {
continue;
}
minChannels=ma_clamp(minChannels,MA_MIN_CHANNELS,MA_MAX_CHANNELS);
maxChannels=ma_clamp(maxChannels,MA_MIN_CHANNELS,MA_MAX_CHANNELS);
if (minChannels==MA_MIN_CHANNELS&&maxChannels==MA_MAX_CHANNELS) {
ma_context_iterate_rates_and_add_native_data_format__alsa(Mc,pPCM,pHWParams,format,0,0,pDeviceInfo);
} else {
for (iChannel=minChannels; iChannel<=maxChannels; iChannel+=1) {
 unsigned int Mh=iChannel;
 ((ma_snd_pcm_hw_params_any_proc)Mc->alsa.snd_pcm_hw_params_any)(pPCM,pHWParams);
 ((ma_snd_pcm_hw_params_set_format_proc)Mc->alsa.snd_pcm_hw_params_set_format)(pPCM,pHWParams,ma_convert_ma_format_to_alsa_format(format));
 if (((ma_snd_pcm_hw_params_test_channels_proc)Mc->alsa.snd_pcm_hw_params_test_channels)(pPCM,pHWParams,Mh)==0) {
 ((ma_snd_pcm_hw_params_set_channels_proc)Mc->alsa.snd_pcm_hw_params_set_channels)(pPCM,pHWParams,Mh);
 ma_context_iterate_rates_and_add_native_data_format__alsa(Mc,pPCM,pHWParams,format,Mh,0,pDeviceInfo);
 } else {
 }
}
}
} else {
}
}
ma_free(pHWParams,&Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Mc->alsa.snd_pcm_close)(pPCM);
Mr Ms;
}
static Me ma_device_uninit__alsa(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if ((ma_snd_pcm_t*)Md->alsa.pPCMCapture) {
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)((ma_snd_pcm_t*)Md->alsa.pPCMCapture);
close(Md->alsa.wakeupfdCapture);
ma_free(Md->alsa.pPollDescriptorsCapture,&Md->Mc->allocationCallbacks);
}
if ((ma_snd_pcm_t*)Md->alsa.pPCMPlayback) {
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback);
close(Md->alsa.wakeupfdPlayback);
ma_free(Md->alsa.pPollDescriptorsPlayback,&Md->Mc->allocationCallbacks);
}
Mr Ms;
}
static Me ma_device_init_by_type__alsa(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*pDescriptor,ma_device_type deviceType)
{
Me Mf;
int resultALSA;
ma_snd_pcm_t*pPCM;
ma_bool32 isUsingMMap;
ma_snd_pcm_format_t formatALSA;
ma_format internalFormat;
M3 internalChannels;
M3 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
M3 internalPeriodSizeInFrames;
M3 internalPeriods;
int openMode;
ma_snd_pcm_hw_params_t*pHWParams;
ma_snd_pcm_sw_params_t*pSWParams;
ma_snd_pcm_uframes_t bufferBoundary;
int pollDescriptorCount;
struct pollfd*pPollDescriptors;
int wakeupfd;
MA_ASSERT(Mo !=NULL);
MA_ASSERT(deviceType !=ma_device_type_duplex);
MA_ASSERT(Md !=NULL);
formatALSA=ma_convert_ma_format_to_alsa_format(pDescriptor->format);
openMode=0;
if (Mo->alsa.noAutoResample) {
openMode|=MA_SND_PCM_NO_AUTO_RESAMPLE;
}
if (Mo->alsa.noAutoChannels) {
openMode|=MA_SND_PCM_NO_AUTO_CHANNELS;
}
if (Mo->alsa.noAutoFormat) {
openMode|=MA_SND_PCM_NO_AUTO_FORMAT;
}
Mf=ma_context_open_pcm__alsa(Md->Mc,pDescriptor->shareMode,deviceType,pDescriptor->pDeviceID,openMode,&pPCM);
if (Mf !=Ms) {
Mr Mf;
}
pHWParams=(ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)Md->Mc->alsa.snd_pcm_hw_params_sizeof)(),&Md->Mc->allocationCallbacks);
if (pHWParams==NULL) {
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for hardware parameters.");
Mr MA_OUT_OF_MEMORY;
}
resultALSA=((ma_snd_pcm_hw_params_any_proc)Md->Mc->alsa.snd_pcm_hw_params_any)(pPCM,pHWParams);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.");
Mr ma_result_from_errno(-resultALSA);
}
isUsingMMap=MA_FALSE;
#if 0
if (deviceType !=ma_device_type_capture) {
if (!Mo->alsa.noMMap) {
if (((ma_snd_pcm_hw_params_set_access_proc)Md->Mc->alsa.snd_pcm_hw_params_set_access)(pPCM,pHWParams,MA_SND_PCM_ACCESS_MMAP_INTERLEAVED)==0) {
Md->alsa.isUsingMMap=MA_TRUE;
}
}
}
#endif
if (!isUsingMMap) {
resultALSA=((ma_snd_pcm_hw_params_set_access_proc)Md->Mc->alsa.snd_pcm_hw_params_set_access)(pPCM,pHWParams,MA_SND_PCM_ACCESS_RW_INTERLEAVED);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.");
Mr ma_result_from_errno(-resultALSA);
}
}
{
if (formatALSA==MA_SND_PCM_FORMAT_UNKNOWN||((ma_snd_pcm_hw_params_test_format_proc)Md->Mc->alsa.snd_pcm_hw_params_test_format)(pPCM,pHWParams,formatALSA) !=0) {
size_t iFormat;
formatALSA=MA_SND_PCM_FORMAT_UNKNOWN;
for (iFormat=0; iFormat<ma_countof(g_maFormatPriorities);++iFormat) {
if (((ma_snd_pcm_hw_params_test_format_proc)Md->Mc->alsa.snd_pcm_hw_params_test_format)(pPCM,pHWParams,ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat]))==0) {
 formatALSA=ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat]);
 break;
}
}
if (formatALSA==MA_SND_PCM_FORMAT_UNKNOWN) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.");
Mr MA_FORMAT_NOT_SUPPORTED;
}
}
resultALSA=((ma_snd_pcm_hw_params_set_format_proc)Md->Mc->alsa.snd_pcm_hw_params_set_format)(pPCM,pHWParams,formatALSA);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.");
Mr ma_result_from_errno(-resultALSA);
}
internalFormat=ma_format_from_alsa(formatALSA);
if (internalFormat==ma_format_unknown) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.");
Mr MA_FORMAT_NOT_SUPPORTED;
}
}
{
unsigned int Mh=pDescriptor->Mh;
if (Mh==0) {
Mh=MA_DEFAULT_CHANNELS;
}
resultALSA=((ma_snd_pcm_hw_params_set_channels_near_proc)Md->Mc->alsa.snd_pcm_hw_params_set_channels_near)(pPCM,pHWParams,&Mh);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.");
Mr ma_result_from_errno(-resultALSA);
}
internalChannels=(M3)Mh;
}
{
unsigned int sampleRate;
((ma_snd_pcm_hw_params_set_rate_resample_proc)Md->Mc->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM,pHWParams,0);
sampleRate=pDescriptor->sampleRate;
if (sampleRate==0) {
sampleRate=MA_DEFAULT_SAMPLE_RATE;
}
resultALSA=((ma_snd_pcm_hw_params_set_rate_near_proc)Md->Mc->alsa.snd_pcm_hw_params_set_rate_near)(pPCM,pHWParams,&sampleRate,0);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.");
Mr ma_result_from_errno(-resultALSA);
}
internalSampleRate=(M3)sampleRate;
}
{
M3 periods=pDescriptor->periodCount;
resultALSA=((ma_snd_pcm_hw_params_set_periods_near_proc)Md->Mc->alsa.snd_pcm_hw_params_set_periods_near)(pPCM,pHWParams,&periods,NULL);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.");
Mr ma_result_from_errno(-resultALSA);
}
internalPeriods=periods;
}
{
ma_snd_pcm_uframes_t actualBufferSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,internalSampleRate,Mo->performanceProfile)*internalPeriods;
resultALSA=((ma_snd_pcm_hw_params_set_buffer_size_near_proc)Md->Mc->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM,pHWParams,&actualBufferSizeInFrames);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.");
Mr ma_result_from_errno(-resultALSA);
}
internalPeriodSizeInFrames=actualBufferSizeInFrames / internalPeriods;
}
resultALSA=((ma_snd_pcm_hw_params_proc)Md->Mc->alsa.snd_pcm_hw_params)(pPCM,pHWParams);
if (resultALSA<0) {
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.");
Mr ma_result_from_errno(-resultALSA);
}
ma_free(pHWParams,&Md->Mc->allocationCallbacks);
pHWParams=NULL;
pSWParams=(ma_snd_pcm_sw_params_t*)ma_calloc(((ma_snd_pcm_sw_params_sizeof_proc)Md->Mc->alsa.snd_pcm_sw_params_sizeof)(),&Md->Mc->allocationCallbacks);
if (pSWParams==NULL) {
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for software parameters.");
Mr MA_OUT_OF_MEMORY;
}
resultALSA=((ma_snd_pcm_sw_params_current_proc)Md->Mc->alsa.snd_pcm_sw_params_current)(pPCM,pSWParams);
if (resultALSA<0) {
ma_free(pSWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.");
Mr ma_result_from_errno(-resultALSA);
}
resultALSA=((ma_snd_pcm_sw_params_set_avail_min_proc)Md->Mc->alsa.snd_pcm_sw_params_set_avail_min)(pPCM,pSWParams,ma_prev_power_of_2(internalPeriodSizeInFrames));
if (resultALSA<0) {
ma_free(pSWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.");
Mr ma_result_from_errno(-resultALSA);
}
resultALSA=((ma_snd_pcm_sw_params_get_boundary_proc)Md->Mc->alsa.snd_pcm_sw_params_get_boundary)(pSWParams,&bufferBoundary);
if (resultALSA<0) {
bufferBoundary=internalPeriodSizeInFrames*internalPeriods;
}
if (deviceType==Mt&&!isUsingMMap) {
resultALSA=((ma_snd_pcm_sw_params_set_start_threshold_proc)Md->Mc->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM,pSWParams,internalPeriodSizeInFrames*2);
if (resultALSA<0) {
ma_free(pSWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.");
Mr ma_result_from_errno(-resultALSA);
}
resultALSA=((ma_snd_pcm_sw_params_set_stop_threshold_proc)Md->Mc->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM,pSWParams,bufferBoundary);
if (resultALSA<0) {
ma_free(pSWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.");
Mr ma_result_from_errno(-resultALSA);
}
}
resultALSA=((ma_snd_pcm_sw_params_proc)Md->Mc->alsa.snd_pcm_sw_params)(pPCM,pSWParams);
if (resultALSA<0) {
ma_free(pSWParams,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.");
Mr ma_result_from_errno(-resultALSA);
}
ma_free(pSWParams,&Md->Mc->allocationCallbacks);
pSWParams=NULL;
{
ma_snd_pcm_chmap_t*pChmap=NULL;
if (Md->Mc->alsa.snd_pcm_get_chmap !=NULL) {
pChmap=((ma_snd_pcm_get_chmap_proc)Md->Mc->alsa.snd_pcm_get_chmap)(pPCM);
}
if (pChmap !=NULL) {
M3 iChannel;
if (pChmap->Mh>=internalChannels) {
for (iChannel=0; iChannel<internalChannels;++iChannel) {
 internalChannelMap[iChannel]=ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
}
} else {
M3 i;
ma_bool32 isValid=MA_TRUE;
ma_channel_map_init_standard(ma_standard_channel_map_alsa,internalChannelMap,ma_countof(internalChannelMap),internalChannels);
for (iChannel=0; iChannel<pChmap->Mh;++iChannel) {
 internalChannelMap[iChannel]=ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
}
for (i=0; i<internalChannels&&isValid;++i) {
 M3 j;
 for (j=i+1; j<internalChannels;++j) {
 if (internalChannelMap[i]==internalChannelMap[j]) {
 isValid=MA_FALSE;
 break;
 }
 }
}
if (!isValid) {
 ma_channel_map_init_standard(ma_standard_channel_map_alsa,internalChannelMap,ma_countof(internalChannelMap),internalChannels);
}
}
free(pChmap);
pChmap=NULL;
} else {
ma_channel_map_init_standard(ma_standard_channel_map_alsa,internalChannelMap,ma_countof(internalChannelMap),internalChannels);
}
}
pollDescriptorCount=((ma_snd_pcm_poll_descriptors_count_proc)Md->Mc->alsa.snd_pcm_poll_descriptors_count)(pPCM);
if (pollDescriptorCount<=0) {
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors count.");
Mr MA_ERROR;
}
pPollDescriptors=(struct pollfd*)ma_malloc(sizeof(*pPollDescriptors)*(pollDescriptorCount+1),&Md->Mc->allocationCallbacks);
if (pPollDescriptors==NULL) {
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for poll descriptors.");
Mr MA_OUT_OF_MEMORY;
}
wakeupfd=eventfd(0,0);
if (wakeupfd<0) {
ma_free(pPollDescriptors,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to create eventfd for poll wakeup.");
Mr ma_result_from_errno(errno);
}
pPollDescriptors[0].fd=wakeupfd;
pPollDescriptors[0].events=POLLIN;
pPollDescriptors[0].revents=0;
pollDescriptorCount=((ma_snd_pcm_poll_descriptors_proc)Md->Mc->alsa.snd_pcm_poll_descriptors)(pPCM,pPollDescriptors+1,pollDescriptorCount);
if (pollDescriptorCount<=0) {
close(wakeupfd);
ma_free(pPollDescriptors,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors.");
Mr MA_ERROR;
}
if (deviceType==ma_device_type_capture) {
Md->alsa.pollDescriptorCountCapture=pollDescriptorCount;
Md->alsa.pPollDescriptorsCapture=pPollDescriptors;
Md->alsa.wakeupfdCapture=wakeupfd;
} else {
Md->alsa.pollDescriptorCountPlayback=pollDescriptorCount;
Md->alsa.pPollDescriptorsPlayback=pPollDescriptors;
Md->alsa.wakeupfdPlayback=wakeupfd;
}
resultALSA=((ma_snd_pcm_prepare_proc)Md->Mc->alsa.snd_pcm_prepare)(pPCM);
if (resultALSA<0) {
close(wakeupfd);
ma_free(pPollDescriptors,&Md->Mc->allocationCallbacks);
((ma_snd_pcm_close_proc)Md->Mc->alsa.snd_pcm_close)(pPCM);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.");
Mr ma_result_from_errno(-resultALSA);
}
if (deviceType==ma_device_type_capture) {
Md->alsa.pPCMCapture=(ma_ptr)pPCM;
Md->alsa.isUsingMMapCapture=isUsingMMap;
} else {
Md->alsa.pPCMPlayback=(ma_ptr)pPCM;
Md->alsa.isUsingMMapPlayback=isUsingMMap;
}
pDescriptor->format=internalFormat;
pDescriptor->Mh=internalChannels;
pDescriptor->sampleRate=internalSampleRate;
ma_channel_map_copy(pDescriptor->channelMap,internalChannelMap,ma_min(internalChannels,MA_MAX_CHANNELS));
pDescriptor->periodSizeInFrames=internalPeriodSizeInFrames;
pDescriptor->periodCount=internalPeriods;
Mr Ms;
}
static Me ma_device_init__alsa(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->alsa);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_by_type__alsa(Md,Mo,pDescriptorCapture,ma_device_type_capture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_by_type__alsa(Md,Mo,Mp,Mt);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_start__alsa(ma_device*Md)
{
int resultALSA;
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
resultALSA=((ma_snd_pcm_start_proc)Md->Mc->alsa.snd_pcm_start)((ma_snd_pcm_t*)Md->alsa.pPCMCapture);
if (resultALSA<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.");
Mr ma_result_from_errno(-resultALSA);
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
resultALSA=((ma_snd_pcm_start_proc)Md->Mc->alsa.snd_pcm_start)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback);
if (resultALSA<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start playback device.");
Mr ma_result_from_errno(-resultALSA);
}
}
Mr Ms;
}
static Me ma_device_stop__alsa(ma_device*Md)
{
int resultPoll;
int resultRead;
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n");
((ma_snd_pcm_drop_proc)Md->Mc->alsa.snd_pcm_drop)((ma_snd_pcm_t*)Md->alsa.pPCMCapture);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device successful.\n");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device...\n");
if (((ma_snd_pcm_prepare_proc)Md->Mc->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)Md->alsa.pPCMCapture)<0) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device failed.\n");
} else {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n");
}
resultPoll=poll((struct pollfd*)Md->alsa.pPollDescriptorsCapture,1,0);
if (resultPoll>0) {
M6 t;
resultRead=read(((struct pollfd*)Md->alsa.pPollDescriptorsCapture)[0].fd,&t,sizeof(t));
if (resultRead !=sizeof(t)) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from capture wakeupfd. read() = %d\n", resultRead);
}
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device...\n");
((ma_snd_pcm_drop_proc)Md->Mc->alsa.snd_pcm_drop)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device successful.\n");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device...\n");
if (((ma_snd_pcm_prepare_proc)Md->Mc->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback)<0) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device failed.\n");
} else {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.\n");
}
resultPoll=poll((struct pollfd*)Md->alsa.pPollDescriptorsPlayback,1,0);
if (resultPoll>0) {
M6 t;
resultRead=read(((struct pollfd*)Md->alsa.pPollDescriptorsPlayback)[0].fd,&t,sizeof(t));
if (resultRead !=sizeof(t)) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from playback wakeupfd. read() = %d\n", resultRead);
}
}
}
Mr Ms;
}
static Me ma_device_wait__alsa(ma_device*Md,ma_snd_pcm_t*pPCM,struct pollfd*pPollDescriptors,int pollDescriptorCount,short requiredEvent)
{
for (;;) {
unsigned short revents;
int resultALSA;
int resultPoll=poll(pPollDescriptors,pollDescriptorCount,-1);
if (resultPoll<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[ALSA] poll() failed.\n");
continue;
}
if ((pPollDescriptors[0].revents&POLLIN) !=0) {
M6 t;
int resultRead=read(pPollDescriptors[0].fd,&t,sizeof(t));
if (resultRead<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] read() failed.\n");
Mr ma_result_from_errno(errno);
}
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] POLLIN set for wakeupfd\n");
Mr MA_DEVICE_NOT_STARTED;
}
resultALSA=((ma_snd_pcm_poll_descriptors_revents_proc)Md->Mc->alsa.snd_pcm_poll_descriptors_revents)(pPCM,pPollDescriptors+1,pollDescriptorCount-1,&revents);
if (resultALSA<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed.\n");
Mr ma_result_from_errno(-resultALSA);
}
if ((revents&POLLERR) !=0) {
ma_snd_pcm_state_t state=((ma_snd_pcm_state_proc)Md->Mc->alsa.snd_pcm_state)(pPCM);
if (state==MA_SND_PCM_STATE_XRUN) {
} else {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[ALSA] POLLERR detected. status = %d\n", ((ma_snd_pcm_state_proc)Md->Mc->alsa.snd_pcm_state)(pPCM));
}
}
if ((revents&requiredEvent)==requiredEvent) {
break;
}
}
Mr Ms;
}
static Me ma_device_wait_read__alsa(ma_device*Md)
{
Mr ma_device_wait__alsa(Md,(ma_snd_pcm_t*)Md->alsa.pPCMCapture,(struct pollfd*)Md->alsa.pPollDescriptorsCapture,Md->alsa.pollDescriptorCountCapture+1,POLLIN);
}
static Me ma_device_wait_write__alsa(ma_device*Md)
{
Mr ma_device_wait__alsa(Md,(ma_snd_pcm_t*)Md->alsa.pPCMPlayback,(struct pollfd*)Md->alsa.pPollDescriptorsPlayback,Md->alsa.pollDescriptorCountPlayback+1,POLLOUT);
}
static Me ma_device_read__alsa(ma_device*Md,Mv*pFramesOut,M3 frameCount,M3*pFramesRead)
{
ma_snd_pcm_sframes_t resultALSA=0;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pFramesOut !=NULL);
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
while (ma_device_get_state(Md)==ma_device_state_started) {
Me Mf;
Mf=ma_device_wait_read__alsa(Md);
if (Mf !=Ms) {
Mr Mf;
}
resultALSA=((ma_snd_pcm_readi_proc)Md->Mc->alsa.snd_pcm_readi)((ma_snd_pcm_t*)Md->alsa.pPCMCapture,pFramesOut,frameCount);
if (resultALSA>=0) {
break;
} else {
if (resultALSA==-EAGAIN) {
continue;
} else if (resultALSA==-EPIPE) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n");
resultALSA=((ma_snd_pcm_recover_proc)Md->Mc->alsa.snd_pcm_recover)((ma_snd_pcm_t*)Md->alsa.pPCMCapture,resultALSA,MA_TRUE);
if (resultALSA<0) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.");
 Mr ma_result_from_errno((int)-resultALSA);
}
resultALSA=((ma_snd_pcm_start_proc)Md->Mc->alsa.snd_pcm_start)((ma_snd_pcm_t*)Md->alsa.pPCMCapture);
if (resultALSA<0) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.");
 Mr ma_result_from_errno((int)-resultALSA);
}
continue;
}
}
}
if (pFramesRead !=NULL) {
*pFramesRead=resultALSA;
}
Mr Ms;
}
static Me ma_device_write__alsa(ma_device*Md,const Mv*pFrames,M3 frameCount,M3*pFramesWritten)
{
ma_snd_pcm_sframes_t resultALSA=0;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pFrames !=NULL);
if (pFramesWritten !=NULL) {
*pFramesWritten=0;
}
while (ma_device_get_state(Md)==ma_device_state_started) {
Me Mf;
Mf=ma_device_wait_write__alsa(Md);
if (Mf !=Ms) {
Mr Mf;
}
resultALSA=((ma_snd_pcm_writei_proc)Md->Mc->alsa.snd_pcm_writei)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback,pFrames,frameCount);
if (resultALSA>=0) {
break;
} else {
if (resultALSA==-EAGAIN) {
continue;
} else if (resultALSA==-EPIPE) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n");
resultALSA=((ma_snd_pcm_recover_proc)Md->Mc->alsa.snd_pcm_recover)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback,resultALSA,MA_TRUE);
if (resultALSA<0) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.");
 Mr ma_result_from_errno((int)-resultALSA);
}
resultALSA=((ma_snd_pcm_start_proc)Md->Mc->alsa.snd_pcm_start)((ma_snd_pcm_t*)Md->alsa.pPCMPlayback);
if (resultALSA<0) {
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.");
 Mr ma_result_from_errno((int)-resultALSA);
}
continue;
}
}
}
if (pFramesWritten !=NULL) {
*pFramesWritten=resultALSA;
}
Mr Ms;
}
static Me ma_device_data_loop_wakeup__alsa(ma_device*Md)
{
M6 t=1;
int resultWrite=0;
MA_ASSERT(Md !=NULL);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up...\n");
if (Md->alsa.pPollDescriptorsCapture !=NULL) {
resultWrite=write(Md->alsa.wakeupfdCapture,&t,sizeof(t));
}
if (Md->alsa.pPollDescriptorsPlayback !=NULL) {
resultWrite=write(Md->alsa.wakeupfdPlayback,&t,sizeof(t));
}
if (resultWrite<0) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[ALSA] write() failed.\n");
Mr ma_result_from_errno(errno);
}
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up completed successfully.\n");
Mr Ms;
}
static Me ma_context_uninit__alsa(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_alsa);
((ma_snd_config_update_free_global_proc)Mc->alsa.snd_config_update_free_global)();
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(ma_context_get_log(Mc),Mc->alsa.asoundSO);
#endif
ma_mutex_uninit(&Mc->alsa.internalDeviceEnumLock);
Mr Ms;
}
static Me ma_context_init__alsa(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
Me Mf;
#ifndef MA_NO_RUNTIME_LINKING
const char*libasoundNames[]={
"libasound.so.2","libasound.so"
};
size_t i;
for (i=0; i<ma_countof(libasoundNames);++i) {
Mc->alsa.asoundSO=ma_dlopen(ma_context_get_log(Mc),libasoundNames[i]);
if (Mc->alsa.asoundSO !=NULL) {
break;
}
}
if (Mc->alsa.asoundSO==NULL) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to open shared object.\n");
Mr MA_NO_BACKEND;
}
Mc->alsa.snd_pcm_open = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_open");
Mc->alsa.snd_pcm_close = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_close");
Mc->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_sizeof");
Mc->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_any");
Mc->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_format");
Mc->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_format_first");
Mc->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask");
Mc->alsa.snd_pcm_hw_params_set_channels = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_channels");
Mc->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near");
Mc->alsa.snd_pcm_hw_params_set_channels_minmax = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_channels_minmax");
Mc->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample");
Mc->alsa.snd_pcm_hw_params_set_rate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_rate");
Mc->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near");
Mc->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near");
Mc->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near");
Mc->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_set_access");
Mc->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_format");
Mc->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_channels");
Mc->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min");
Mc->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max");
Mc->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_rate");
Mc->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min");
Mc->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max");
Mc->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size");
Mc->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_periods");
Mc->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_get_access");
Mc->alsa.snd_pcm_hw_params_test_format = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_test_format");
Mc->alsa.snd_pcm_hw_params_test_channels = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_test_channels");
Mc->alsa.snd_pcm_hw_params_test_rate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params_test_rate");
Mc->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_hw_params");
Mc->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params_sizeof");
Mc->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params_current");
Mc->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params_get_boundary");
Mc->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min");
Mc->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold");
Mc->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold");
Mc->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_sw_params");
Mc->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_format_mask_sizeof");
Mc->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_format_mask_test");
Mc->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_get_chmap");
Mc->alsa.snd_pcm_state = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_state");
Mc->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_prepare");
Mc->alsa.snd_pcm_start = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_start");
Mc->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_drop");
Mc->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_drain");
Mc->alsa.snd_pcm_reset = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_reset");
Mc->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_device_name_hint");
Mc->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_device_name_get_hint");
Mc->alsa.snd_card_get_index = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_card_get_index");
Mc->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_device_name_free_hint");
Mc->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_mmap_begin");
Mc->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_mmap_commit");
Mc->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_recover");
Mc->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_readi");
Mc->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_writei");
Mc->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_avail");
Mc->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_avail_update");
Mc->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_wait");
Mc->alsa.snd_pcm_nonblock = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_nonblock");
Mc->alsa.snd_pcm_info = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_info");
Mc->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_info_sizeof");
Mc->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_info_get_name");
Mc->alsa.snd_pcm_poll_descriptors = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_poll_descriptors");
Mc->alsa.snd_pcm_poll_descriptors_count = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_poll_descriptors_count");
Mc->alsa.snd_pcm_poll_descriptors_revents = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_pcm_poll_descriptors_revents");
Mc->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->alsa.asoundSO, "snd_config_update_free_global");
#else
ma_snd_pcm_open_proc _snd_pcm_open=snd_pcm_open;
ma_snd_pcm_close_proc _snd_pcm_close=snd_pcm_close;
ma_snd_pcm_hw_params_sizeof_proc _snd_pcm_hw_params_sizeof=snd_pcm_hw_params_sizeof;
ma_snd_pcm_hw_params_any_proc _snd_pcm_hw_params_any=snd_pcm_hw_params_any;
ma_snd_pcm_hw_params_set_format_proc _snd_pcm_hw_params_set_format=snd_pcm_hw_params_set_format;
ma_snd_pcm_hw_params_set_format_first_proc _snd_pcm_hw_params_set_format_first=snd_pcm_hw_params_set_format_first;
ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask=snd_pcm_hw_params_get_format_mask;
ma_snd_pcm_hw_params_set_channels_proc _snd_pcm_hw_params_set_channels=snd_pcm_hw_params_set_channels;
ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near=snd_pcm_hw_params_set_channels_near;
ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample=snd_pcm_hw_params_set_rate_resample;
ma_snd_pcm_hw_params_set_rate_near _snd_pcm_hw_params_set_rate=snd_pcm_hw_params_set_rate;
ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near=snd_pcm_hw_params_set_rate_near;
ma_snd_pcm_hw_params_set_rate_minmax_proc _snd_pcm_hw_params_set_rate_minmax=snd_pcm_hw_params_set_rate_minmax;
ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near=snd_pcm_hw_params_set_buffer_size_near;
ma_snd_pcm_hw_params_set_periods_near_proc _snd_pcm_hw_params_set_periods_near=snd_pcm_hw_params_set_periods_near;
ma_snd_pcm_hw_params_set_access_proc _snd_pcm_hw_params_set_access=snd_pcm_hw_params_set_access;
ma_snd_pcm_hw_params_get_format_proc _snd_pcm_hw_params_get_format=snd_pcm_hw_params_get_format;
ma_snd_pcm_hw_params_get_channels_proc _snd_pcm_hw_params_get_channels=snd_pcm_hw_params_get_channels;
ma_snd_pcm_hw_params_get_channels_min_proc _snd_pcm_hw_params_get_channels_min=snd_pcm_hw_params_get_channels_min;
ma_snd_pcm_hw_params_get_channels_max_proc _snd_pcm_hw_params_get_channels_max=snd_pcm_hw_params_get_channels_max;
ma_snd_pcm_hw_params_get_rate_proc _snd_pcm_hw_params_get_rate=snd_pcm_hw_params_get_rate;
ma_snd_pcm_hw_params_get_rate_min_proc _snd_pcm_hw_params_get_rate_min=snd_pcm_hw_params_get_rate_min;
ma_snd_pcm_hw_params_get_rate_max_proc _snd_pcm_hw_params_get_rate_max=snd_pcm_hw_params_get_rate_max;
ma_snd_pcm_hw_params_get_buffer_size_proc _snd_pcm_hw_params_get_buffer_size=snd_pcm_hw_params_get_buffer_size;
ma_snd_pcm_hw_params_get_periods_proc _snd_pcm_hw_params_get_periods=snd_pcm_hw_params_get_periods;
ma_snd_pcm_hw_params_get_access_proc _snd_pcm_hw_params_get_access=snd_pcm_hw_params_get_access;
ma_snd_pcm_hw_params_test_format_proc _snd_pcm_hw_params_test_format=snd_pcm_hw_params_test_format;
ma_snd_pcm_hw_params_test_channels_proc _snd_pcm_hw_params_test_channels=snd_pcm_hw_params_test_channels;
ma_snd_pcm_hw_params_test_rate_proc _snd_pcm_hw_params_test_rate=snd_pcm_hw_params_test_rate;
ma_snd_pcm_hw_params_proc _snd_pcm_hw_params=snd_pcm_hw_params;
ma_snd_pcm_sw_params_sizeof_proc _snd_pcm_sw_params_sizeof=snd_pcm_sw_params_sizeof;
ma_snd_pcm_sw_params_current_proc _snd_pcm_sw_params_current=snd_pcm_sw_params_current;
ma_snd_pcm_sw_params_get_boundary_proc _snd_pcm_sw_params_get_boundary=snd_pcm_sw_params_get_boundary;
ma_snd_pcm_sw_params_set_avail_min_proc _snd_pcm_sw_params_set_avail_min=snd_pcm_sw_params_set_avail_min;
ma_snd_pcm_sw_params_set_start_threshold_proc _snd_pcm_sw_params_set_start_threshold=snd_pcm_sw_params_set_start_threshold;
ma_snd_pcm_sw_params_set_stop_threshold_proc _snd_pcm_sw_params_set_stop_threshold=snd_pcm_sw_params_set_stop_threshold;
ma_snd_pcm_sw_params_proc _snd_pcm_sw_params=snd_pcm_sw_params;
ma_snd_pcm_format_mask_sizeof_proc _snd_pcm_format_mask_sizeof=snd_pcm_format_mask_sizeof;
ma_snd_pcm_format_mask_test_proc _snd_pcm_format_mask_test=snd_pcm_format_mask_test;
ma_snd_pcm_get_chmap_proc _snd_pcm_get_chmap=snd_pcm_get_chmap;
ma_snd_pcm_state_proc _snd_pcm_state=snd_pcm_state;
ma_snd_pcm_prepare_proc _snd_pcm_prepare=snd_pcm_prepare;
ma_snd_pcm_start_proc _snd_pcm_start=snd_pcm_start;
ma_snd_pcm_drop_proc _snd_pcm_drop=snd_pcm_drop;
ma_snd_pcm_drain_proc _snd_pcm_drain=snd_pcm_drain;
ma_snd_pcm_reset_proc _snd_pcm_reset=snd_pcm_reset;
ma_snd_device_name_hint_proc _snd_device_name_hint=snd_device_name_hint;
ma_snd_device_name_get_hint_proc _snd_device_name_get_hint=snd_device_name_get_hint;
ma_snd_card_get_index_proc _snd_card_get_index=snd_card_get_index;
ma_snd_device_name_free_hint_proc _snd_device_name_free_hint=snd_device_name_free_hint;
ma_snd_pcm_mmap_begin_proc _snd_pcm_mmap_begin=snd_pcm_mmap_begin;
ma_snd_pcm_mmap_commit_proc _snd_pcm_mmap_commit=snd_pcm_mmap_commit;
ma_snd_pcm_recover_proc _snd_pcm_recover=snd_pcm_recover;
ma_snd_pcm_readi_proc _snd_pcm_readi=snd_pcm_readi;
ma_snd_pcm_writei_proc _snd_pcm_writei=snd_pcm_writei;
ma_snd_pcm_avail_proc _snd_pcm_avail=snd_pcm_avail;
ma_snd_pcm_avail_update_proc _snd_pcm_avail_update=snd_pcm_avail_update;
ma_snd_pcm_wait_proc _snd_pcm_wait=snd_pcm_wait;
ma_snd_pcm_nonblock_proc _snd_pcm_nonblock=snd_pcm_nonblock;
ma_snd_pcm_info_proc _snd_pcm_info=snd_pcm_info;
ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof=snd_pcm_info_sizeof;
ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name=snd_pcm_info_get_name;
ma_snd_pcm_poll_descriptors _snd_pcm_poll_descriptors=snd_pcm_poll_descriptors;
ma_snd_pcm_poll_descriptors_count _snd_pcm_poll_descriptors_count=snd_pcm_poll_descriptors_count;
ma_snd_pcm_poll_descriptors_revents _snd_pcm_poll_descriptors_revents=snd_pcm_poll_descriptors_revents;
ma_snd_config_update_free_global_proc _snd_config_update_free_global=snd_config_update_free_global;
Mc->alsa.snd_pcm_open=(ma_proc)_snd_pcm_open;
Mc->alsa.snd_pcm_close=(ma_proc)_snd_pcm_close;
Mc->alsa.snd_pcm_hw_params_sizeof=(ma_proc)_snd_pcm_hw_params_sizeof;
Mc->alsa.snd_pcm_hw_params_any=(ma_proc)_snd_pcm_hw_params_any;
Mc->alsa.snd_pcm_hw_params_set_format=(ma_proc)_snd_pcm_hw_params_set_format;
Mc->alsa.snd_pcm_hw_params_set_format_first=(ma_proc)_snd_pcm_hw_params_set_format_first;
Mc->alsa.snd_pcm_hw_params_get_format_mask=(ma_proc)_snd_pcm_hw_params_get_format_mask;
Mc->alsa.snd_pcm_hw_params_set_channels=(ma_proc)_snd_pcm_hw_params_set_channels;
Mc->alsa.snd_pcm_hw_params_set_channels_near=(ma_proc)_snd_pcm_hw_params_set_channels_near;
Mc->alsa.snd_pcm_hw_params_set_channels_minmax=(ma_proc)_snd_pcm_hw_params_set_channels_minmax;
Mc->alsa.snd_pcm_hw_params_set_rate_resample=(ma_proc)_snd_pcm_hw_params_set_rate_resample;
Mc->alsa.snd_pcm_hw_params_set_rate=(ma_proc)_snd_pcm_hw_params_set_rate;
Mc->alsa.snd_pcm_hw_params_set_rate_near=(ma_proc)_snd_pcm_hw_params_set_rate_near;
Mc->alsa.snd_pcm_hw_params_set_buffer_size_near=(ma_proc)_snd_pcm_hw_params_set_buffer_size_near;
Mc->alsa.snd_pcm_hw_params_set_periods_near=(ma_proc)_snd_pcm_hw_params_set_periods_near;
Mc->alsa.snd_pcm_hw_params_set_access=(ma_proc)_snd_pcm_hw_params_set_access;
Mc->alsa.snd_pcm_hw_params_get_format=(ma_proc)_snd_pcm_hw_params_get_format;
Mc->alsa.snd_pcm_hw_params_get_channels=(ma_proc)_snd_pcm_hw_params_get_channels;
Mc->alsa.snd_pcm_hw_params_get_channels_min=(ma_proc)_snd_pcm_hw_params_get_channels_min;
Mc->alsa.snd_pcm_hw_params_get_channels_max=(ma_proc)_snd_pcm_hw_params_get_channels_max;
Mc->alsa.snd_pcm_hw_params_get_rate=(ma_proc)_snd_pcm_hw_params_get_rate;
Mc->alsa.snd_pcm_hw_params_get_rate_min=(ma_proc)_snd_pcm_hw_params_get_rate_min;
Mc->alsa.snd_pcm_hw_params_get_rate_max=(ma_proc)_snd_pcm_hw_params_get_rate_max;
Mc->alsa.snd_pcm_hw_params_get_buffer_size=(ma_proc)_snd_pcm_hw_params_get_buffer_size;
Mc->alsa.snd_pcm_hw_params_get_periods=(ma_proc)_snd_pcm_hw_params_get_periods;
Mc->alsa.snd_pcm_hw_params_get_access=(ma_proc)_snd_pcm_hw_params_get_access;
Mc->alsa.snd_pcm_hw_params_test_format=(ma_proc)_snd_pcm_hw_params_test_format;
Mc->alsa.snd_pcm_hw_params_test_channels=(ma_proc)_snd_pcm_hw_params_test_channels;
Mc->alsa.snd_pcm_hw_params_test_rate=(ma_proc)_snd_pcm_hw_params_test_rate;
Mc->alsa.snd_pcm_hw_params=(ma_proc)_snd_pcm_hw_params;
Mc->alsa.snd_pcm_sw_params_sizeof=(ma_proc)_snd_pcm_sw_params_sizeof;
Mc->alsa.snd_pcm_sw_params_current=(ma_proc)_snd_pcm_sw_params_current;
Mc->alsa.snd_pcm_sw_params_get_boundary=(ma_proc)_snd_pcm_sw_params_get_boundary;
Mc->alsa.snd_pcm_sw_params_set_avail_min=(ma_proc)_snd_pcm_sw_params_set_avail_min;
Mc->alsa.snd_pcm_sw_params_set_start_threshold=(ma_proc)_snd_pcm_sw_params_set_start_threshold;
Mc->alsa.snd_pcm_sw_params_set_stop_threshold=(ma_proc)_snd_pcm_sw_params_set_stop_threshold;
Mc->alsa.snd_pcm_sw_params=(ma_proc)_snd_pcm_sw_params;
Mc->alsa.snd_pcm_format_mask_sizeof=(ma_proc)_snd_pcm_format_mask_sizeof;
Mc->alsa.snd_pcm_format_mask_test=(ma_proc)_snd_pcm_format_mask_test;
Mc->alsa.snd_pcm_get_chmap=(ma_proc)_snd_pcm_get_chmap;
Mc->alsa.snd_pcm_state=(ma_proc)_snd_pcm_state;
Mc->alsa.snd_pcm_prepare=(ma_proc)_snd_pcm_prepare;
Mc->alsa.snd_pcm_start=(ma_proc)_snd_pcm_start;
Mc->alsa.snd_pcm_drop=(ma_proc)_snd_pcm_drop;
Mc->alsa.snd_pcm_drain=(ma_proc)_snd_pcm_drain;
Mc->alsa.snd_pcm_reset=(ma_proc)_snd_pcm_reset;
Mc->alsa.snd_device_name_hint=(ma_proc)_snd_device_name_hint;
Mc->alsa.snd_device_name_get_hint=(ma_proc)_snd_device_name_get_hint;
Mc->alsa.snd_card_get_index=(ma_proc)_snd_card_get_index;
Mc->alsa.snd_device_name_free_hint=(ma_proc)_snd_device_name_free_hint;
Mc->alsa.snd_pcm_mmap_begin=(ma_proc)_snd_pcm_mmap_begin;
Mc->alsa.snd_pcm_mmap_commit=(ma_proc)_snd_pcm_mmap_commit;
Mc->alsa.snd_pcm_recover=(ma_proc)_snd_pcm_recover;
Mc->alsa.snd_pcm_readi=(ma_proc)_snd_pcm_readi;
Mc->alsa.snd_pcm_writei=(ma_proc)_snd_pcm_writei;
Mc->alsa.snd_pcm_avail=(ma_proc)_snd_pcm_avail;
Mc->alsa.snd_pcm_avail_update=(ma_proc)_snd_pcm_avail_update;
Mc->alsa.snd_pcm_wait=(ma_proc)_snd_pcm_wait;
Mc->alsa.snd_pcm_nonblock=(ma_proc)_snd_pcm_nonblock;
Mc->alsa.snd_pcm_info=(ma_proc)_snd_pcm_info;
Mc->alsa.snd_pcm_info_sizeof=(ma_proc)_snd_pcm_info_sizeof;
Mc->alsa.snd_pcm_info_get_name=(ma_proc)_snd_pcm_info_get_name;
Mc->alsa.snd_pcm_poll_descriptors=(ma_proc)_snd_pcm_poll_descriptors;
Mc->alsa.snd_pcm_poll_descriptors_count=(ma_proc)_snd_pcm_poll_descriptors_count;
Mc->alsa.snd_pcm_poll_descriptors_revents=(ma_proc)_snd_pcm_poll_descriptors_revents;
Mc->alsa.snd_config_update_free_global=(ma_proc)_snd_config_update_free_global;
#endif
Mc->alsa.useVerboseDeviceEnumeration=Mo->alsa.useVerboseDeviceEnumeration;
Mf=ma_mutex_init(&Mc->alsa.internalDeviceEnumLock);
if (Mf !=Ms) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.");
Mr Mf;
}
pCallbacks->onContextInit=ma_context_init__alsa;
pCallbacks->onContextUninit=ma_context_uninit__alsa;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__alsa;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__alsa;
pCallbacks->onDeviceInit=ma_device_init__alsa;
pCallbacks->onDeviceUninit=ma_device_uninit__alsa;
pCallbacks->onDeviceStart=ma_device_start__alsa;
pCallbacks->onDeviceStop=ma_device_stop__alsa;
pCallbacks->onDeviceRead=ma_device_read__alsa;
pCallbacks->onDeviceWrite=ma_device_write__alsa;
pCallbacks->onDeviceDataLoop=NULL;
pCallbacks->onDeviceDataLoopWakeup=ma_device_data_loop_wakeup__alsa;
Mr Ms;
}
#endif
#ifdef MA_HAS_PULSEAUDIO
#ifdef MA_NO_RUNTIME_LINKING
#if !defined(__cplusplus)
#if defined(__STRICT_ANSI__)
#if !defined(inline)
#define inline __inline__ __attribute__((always_inline))
#define MA_INLINE_DEFINED
#endif
#endif
#endif
#include <pulse/pulseaudio.h>
#if defined(MA_INLINE_DEFINED)
#undef inline
#undef MA_INLINE_DEFINED
#endif
#define MA_PA_OK PA_OK
#define MA_PA_ERR_ACCESS PA_ERR_ACCESS
#define MA_PA_ERR_INVALID PA_ERR_INVALID
#define MA_PA_ERR_NOENTITY PA_ERR_NOENTITY
#define MA_PA_ERR_NOTSUPPORTED PA_ERR_NOTSUPPORTED
#define MA_PA_CHANNELS_MAX PA_CHANNELS_MAX
#define MA_PA_RATE_MAX PA_RATE_MAX
typedef pa_context_flags_t ma_pa_context_flags_t;
#define MA_PA_CONTEXT_NOFLAGS PA_CONTEXT_NOFLAGS
#define MA_PA_CONTEXT_NOAUTOSPAWN PA_CONTEXT_NOAUTOSPAWN
#define MA_PA_CONTEXT_NOFAIL PA_CONTEXT_NOFAIL
typedef pa_stream_flags_t ma_pa_stream_flags_t;
#define MA_PA_STREAM_NOFLAGS PA_STREAM_NOFLAGS
#define MA_PA_STREAM_START_CORKED PA_STREAM_START_CORKED
#define MA_PA_STREAM_INTERPOLATE_TIMING PA_STREAM_INTERPOLATE_TIMING
#define MA_PA_STREAM_NOT_MONOTONIC PA_STREAM_NOT_MONOTONIC
#define MA_PA_STREAM_AUTO_TIMING_UPDATE PA_STREAM_AUTO_TIMING_UPDATE
#define MA_PA_STREAM_NO_REMAP_CHANNELS PA_STREAM_NO_REMAP_CHANNELS
#define MA_PA_STREAM_NO_REMIX_CHANNELS PA_STREAM_NO_REMIX_CHANNELS
#define MA_PA_STREAM_FIX_FORMAT PA_STREAM_FIX_FORMAT
#define MA_PA_STREAM_FIX_RATE PA_STREAM_FIX_RATE
#define MA_PA_STREAM_FIX_CHANNELS PA_STREAM_FIX_CHANNELS
#define MA_PA_STREAM_DONT_MOVE PA_STREAM_DONT_MOVE
#define MA_PA_STREAM_VARIABLE_RATE PA_STREAM_VARIABLE_RATE
#define MA_PA_STREAM_PEAK_DETECT PA_STREAM_PEAK_DETECT
#define MA_PA_STREAM_START_MUTED PA_STREAM_START_MUTED
#define MA_PA_STREAM_ADJUST_LATENCY PA_STREAM_ADJUST_LATENCY
#define MA_PA_STREAM_EARLY_REQUESTS PA_STREAM_EARLY_REQUESTS
#define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
#define MA_PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED
#define MA_PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND
#define MA_PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME
#define MA_PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH
typedef pa_sink_flags_t ma_pa_sink_flags_t;
#define MA_PA_SINK_NOFLAGS PA_SINK_NOFLAGS
#define MA_PA_SINK_HW_VOLUME_CTRL PA_SINK_HW_VOLUME_CTRL
#define MA_PA_SINK_LATENCY PA_SINK_LATENCY
#define MA_PA_SINK_HARDWARE PA_SINK_HARDWARE
#define MA_PA_SINK_NETWORK PA_SINK_NETWORK
#define MA_PA_SINK_HW_MUTE_CTRL PA_SINK_HW_MUTE_CTRL
#define MA_PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME
#define MA_PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME
#define MA_PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY
#define MA_PA_SINK_SET_FORMATS PA_SINK_SET_FORMATS
typedef pa_source_flags_t ma_pa_source_flags_t;
#define MA_PA_SOURCE_NOFLAGS PA_SOURCE_NOFLAGS
#define MA_PA_SOURCE_HW_VOLUME_CTRL PA_SOURCE_HW_VOLUME_CTRL
#define MA_PA_SOURCE_LATENCY PA_SOURCE_LATENCY
#define MA_PA_SOURCE_HARDWARE PA_SOURCE_HARDWARE
#define MA_PA_SOURCE_NETWORK PA_SOURCE_NETWORK
#define MA_PA_SOURCE_HW_MUTE_CTRL PA_SOURCE_HW_MUTE_CTRL
#define MA_PA_SOURCE_DECIBEL_VOLUME PA_SOURCE_DECIBEL_VOLUME
#define MA_PA_SOURCE_DYNAMIC_LATENCY PA_SOURCE_DYNAMIC_LATENCY
#define MA_PA_SOURCE_FLAT_VOLUME PA_SOURCE_FLAT_VOLUME
typedef pa_context_state_t ma_pa_context_state_t;
#define MA_PA_CONTEXT_UNCONNECTED PA_CONTEXT_UNCONNECTED
#define MA_PA_CONTEXT_CONNECTING PA_CONTEXT_CONNECTING
#define MA_PA_CONTEXT_AUTHORIZING PA_CONTEXT_AUTHORIZING
#define MA_PA_CONTEXT_SETTING_NAME PA_CONTEXT_SETTING_NAME
#define MA_PA_CONTEXT_READY PA_CONTEXT_READY
#define MA_PA_CONTEXT_FAILED PA_CONTEXT_FAILED
#define MA_PA_CONTEXT_TERMINATED PA_CONTEXT_TERMINATED
typedef pa_stream_state_t ma_pa_stream_state_t;
#define MA_PA_STREAM_UNCONNECTED PA_STREAM_UNCONNECTED
#define MA_PA_STREAM_CREATING PA_STREAM_CREATING
#define MA_PA_STREAM_READY PA_STREAM_READY
#define MA_PA_STREAM_FAILED PA_STREAM_FAILED
#define MA_PA_STREAM_TERMINATED PA_STREAM_TERMINATED
typedef pa_operation_state_t ma_pa_operation_state_t;
#define MA_PA_OPERATION_RUNNING PA_OPERATION_RUNNING
#define MA_PA_OPERATION_DONE PA_OPERATION_DONE
#define MA_PA_OPERATION_CANCELLED PA_OPERATION_CANCELLED
typedef pa_sink_state_t ma_pa_sink_state_t;
#define MA_PA_SINK_INVALID_STATE PA_SINK_INVALID_STATE
#define MA_PA_SINK_RUNNING PA_SINK_RUNNING
#define MA_PA_SINK_IDLE PA_SINK_IDLE
#define MA_PA_SINK_SUSPENDED PA_SINK_SUSPENDED
typedef pa_source_state_t ma_pa_source_state_t;
#define MA_PA_SOURCE_INVALID_STATE PA_SOURCE_INVALID_STATE
#define MA_PA_SOURCE_RUNNING PA_SOURCE_RUNNING
#define MA_PA_SOURCE_IDLE PA_SOURCE_IDLE
#define MA_PA_SOURCE_SUSPENDED PA_SOURCE_SUSPENDED
typedef pa_seek_mode_t ma_pa_seek_mode_t;
#define MA_PA_SEEK_RELATIVE PA_SEEK_RELATIVE
#define MA_PA_SEEK_ABSOLUTE PA_SEEK_ABSOLUTE
#define MA_PA_SEEK_RELATIVE_ON_READ PA_SEEK_RELATIVE_ON_READ
#define MA_PA_SEEK_RELATIVE_END PA_SEEK_RELATIVE_END
typedef pa_channel_position_t ma_pa_channel_position_t;
#define MA_PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_INVALID
#define MA_PA_CHANNEL_POSITION_MONO PA_CHANNEL_POSITION_MONO
#define MA_PA_CHANNEL_POSITION_FRONT_LEFT PA_CHANNEL_POSITION_FRONT_LEFT
#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT PA_CHANNEL_POSITION_FRONT_RIGHT
#define MA_PA_CHANNEL_POSITION_FRONT_CENTER PA_CHANNEL_POSITION_FRONT_CENTER
#define MA_PA_CHANNEL_POSITION_REAR_CENTER PA_CHANNEL_POSITION_REAR_CENTER
#define MA_PA_CHANNEL_POSITION_REAR_LEFT PA_CHANNEL_POSITION_REAR_LEFT
#define MA_PA_CHANNEL_POSITION_REAR_RIGHT PA_CHANNEL_POSITION_REAR_RIGHT
#define MA_PA_CHANNEL_POSITION_LFE PA_CHANNEL_POSITION_LFE
#define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
#define MA_PA_CHANNEL_POSITION_SIDE_LEFT PA_CHANNEL_POSITION_SIDE_LEFT
#define MA_PA_CHANNEL_POSITION_SIDE_RIGHT PA_CHANNEL_POSITION_SIDE_RIGHT
#define MA_PA_CHANNEL_POSITION_AUX0 PA_CHANNEL_POSITION_AUX0
#define MA_PA_CHANNEL_POSITION_AUX1 PA_CHANNEL_POSITION_AUX1
#define MA_PA_CHANNEL_POSITION_AUX2 PA_CHANNEL_POSITION_AUX2
#define MA_PA_CHANNEL_POSITION_AUX3 PA_CHANNEL_POSITION_AUX3
#define MA_PA_CHANNEL_POSITION_AUX4 PA_CHANNEL_POSITION_AUX4
#define MA_PA_CHANNEL_POSITION_AUX5 PA_CHANNEL_POSITION_AUX5
#define MA_PA_CHANNEL_POSITION_AUX6 PA_CHANNEL_POSITION_AUX6
#define MA_PA_CHANNEL_POSITION_AUX7 PA_CHANNEL_POSITION_AUX7
#define MA_PA_CHANNEL_POSITION_AUX8 PA_CHANNEL_POSITION_AUX8
#define MA_PA_CHANNEL_POSITION_AUX9 PA_CHANNEL_POSITION_AUX9
#define MA_PA_CHANNEL_POSITION_AUX10 PA_CHANNEL_POSITION_AUX10
#define MA_PA_CHANNEL_POSITION_AUX11 PA_CHANNEL_POSITION_AUX11
#define MA_PA_CHANNEL_POSITION_AUX12 PA_CHANNEL_POSITION_AUX12
#define MA_PA_CHANNEL_POSITION_AUX13 PA_CHANNEL_POSITION_AUX13
#define MA_PA_CHANNEL_POSITION_AUX14 PA_CHANNEL_POSITION_AUX14
#define MA_PA_CHANNEL_POSITION_AUX15 PA_CHANNEL_POSITION_AUX15
#define MA_PA_CHANNEL_POSITION_AUX16 PA_CHANNEL_POSITION_AUX16
#define MA_PA_CHANNEL_POSITION_AUX17 PA_CHANNEL_POSITION_AUX17
#define MA_PA_CHANNEL_POSITION_AUX18 PA_CHANNEL_POSITION_AUX18
#define MA_PA_CHANNEL_POSITION_AUX19 PA_CHANNEL_POSITION_AUX19
#define MA_PA_CHANNEL_POSITION_AUX20 PA_CHANNEL_POSITION_AUX20
#define MA_PA_CHANNEL_POSITION_AUX21 PA_CHANNEL_POSITION_AUX21
#define MA_PA_CHANNEL_POSITION_AUX22 PA_CHANNEL_POSITION_AUX22
#define MA_PA_CHANNEL_POSITION_AUX23 PA_CHANNEL_POSITION_AUX23
#define MA_PA_CHANNEL_POSITION_AUX24 PA_CHANNEL_POSITION_AUX24
#define MA_PA_CHANNEL_POSITION_AUX25 PA_CHANNEL_POSITION_AUX25
#define MA_PA_CHANNEL_POSITION_AUX26 PA_CHANNEL_POSITION_AUX26
#define MA_PA_CHANNEL_POSITION_AUX27 PA_CHANNEL_POSITION_AUX27
#define MA_PA_CHANNEL_POSITION_AUX28 PA_CHANNEL_POSITION_AUX28
#define MA_PA_CHANNEL_POSITION_AUX29 PA_CHANNEL_POSITION_AUX29
#define MA_PA_CHANNEL_POSITION_AUX30 PA_CHANNEL_POSITION_AUX30
#define MA_PA_CHANNEL_POSITION_AUX31 PA_CHANNEL_POSITION_AUX31
#define MA_PA_CHANNEL_POSITION_TOP_CENTER PA_CHANNEL_POSITION_TOP_CENTER
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT PA_CHANNEL_POSITION_TOP_FRONT_LEFT
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER PA_CHANNEL_POSITION_TOP_FRONT_CENTER
#define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT PA_CHANNEL_POSITION_TOP_REAR_LEFT
#define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT PA_CHANNEL_POSITION_TOP_REAR_RIGHT
#define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER PA_CHANNEL_POSITION_TOP_REAR_CENTER
#define MA_PA_CHANNEL_POSITION_LEFT PA_CHANNEL_POSITION_LEFT
#define MA_PA_CHANNEL_POSITION_RIGHT PA_CHANNEL_POSITION_RIGHT
#define MA_PA_CHANNEL_POSITION_CENTER PA_CHANNEL_POSITION_CENTER
#define MA_PA_CHANNEL_POSITION_SUBWOOFER PA_CHANNEL_POSITION_SUBWOOFER
typedef pa_channel_map_def_t ma_pa_channel_map_def_t;
#define MA_PA_CHANNEL_MAP_AIFF PA_CHANNEL_MAP_AIFF
#define MA_PA_CHANNEL_MAP_ALSA PA_CHANNEL_MAP_ALSA
#define MA_PA_CHANNEL_MAP_AUX PA_CHANNEL_MAP_AUX
#define MA_PA_CHANNEL_MAP_WAVEEX PA_CHANNEL_MAP_WAVEEX
#define MA_PA_CHANNEL_MAP_OSS PA_CHANNEL_MAP_OSS
#define MA_PA_CHANNEL_MAP_DEFAULT PA_CHANNEL_MAP_DEFAULT
typedef pa_sample_format_t ma_pa_sample_format_t;
#define MA_PA_SAMPLE_INVALID PA_SAMPLE_INVALID
#define MA_PA_SAMPLE_U8 PA_SAMPLE_U8
#define MA_PA_SAMPLE_ALAW PA_SAMPLE_ALAW
#define MA_PA_SAMPLE_ULAW PA_SAMPLE_ULAW
#define MA_PA_SAMPLE_S16LE PA_SAMPLE_S16LE
#define MA_PA_SAMPLE_S16BE PA_SAMPLE_S16BE
#define MA_PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32LE
#define MA_PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE
#define MA_PA_SAMPLE_S32LE PA_SAMPLE_S32LE
#define MA_PA_SAMPLE_S32BE PA_SAMPLE_S32BE
#define MA_PA_SAMPLE_S24LE PA_SAMPLE_S24LE
#define MA_PA_SAMPLE_S24BE PA_SAMPLE_S24BE
#define MA_PA_SAMPLE_S24_32LE PA_SAMPLE_S24_32LE
#define MA_PA_SAMPLE_S24_32BE PA_SAMPLE_S24_32BE
typedef pa_mainloop ma_pa_mainloop;
typedef pa_threaded_mainloop ma_pa_threaded_mainloop;
typedef pa_mainloop_api ma_pa_mainloop_api;
typedef pa_context ma_pa_context;
typedef pa_operation ma_pa_operation;
typedef pa_stream ma_pa_stream;
typedef pa_spawn_api ma_pa_spawn_api;
typedef pa_buffer_attr ma_pa_buffer_attr;
typedef pa_channel_map ma_pa_channel_map;
typedef pa_cvolume ma_pa_cvolume;
typedef pa_sample_spec ma_pa_sample_spec;
typedef pa_sink_info ma_pa_sink_info;
typedef pa_source_info ma_pa_source_info;
typedef pa_context_notify_cb_t ma_pa_context_notify_cb_t;
typedef pa_sink_info_cb_t ma_pa_sink_info_cb_t;
typedef pa_source_info_cb_t ma_pa_source_info_cb_t;
typedef pa_stream_success_cb_t ma_pa_stream_success_cb_t;
typedef pa_stream_request_cb_t ma_pa_stream_request_cb_t;
typedef pa_stream_notify_cb_t ma_pa_stream_notify_cb_t;
typedef pa_free_cb_t ma_pa_free_cb_t;
#else
#define MA_PA_OK 0
#define MA_PA_ERR_ACCESS 1
#define MA_PA_ERR_INVALID 2
#define MA_PA_ERR_NOENTITY 5
#define MA_PA_ERR_NOTSUPPORTED 19
#define MA_PA_CHANNELS_MAX 32
#define MA_PA_RATE_MAX 384000
typedef int ma_pa_context_flags_t;
#define MA_PA_CONTEXT_NOFLAGS 0x00000000
#define MA_PA_CONTEXT_NOAUTOSPAWN 0x00000001
#define MA_PA_CONTEXT_NOFAIL 0x00000002
typedef int ma_pa_stream_flags_t;
#define MA_PA_STREAM_NOFLAGS 0x00000000
#define MA_PA_STREAM_START_CORKED 0x00000001
#define MA_PA_STREAM_INTERPOLATE_TIMING 0x00000002
#define MA_PA_STREAM_NOT_MONOTONIC 0x00000004
#define MA_PA_STREAM_AUTO_TIMING_UPDATE 0x00000008
#define MA_PA_STREAM_NO_REMAP_CHANNELS 0x00000010
#define MA_PA_STREAM_NO_REMIX_CHANNELS 0x00000020
#define MA_PA_STREAM_FIX_FORMAT 0x00000040
#define MA_PA_STREAM_FIX_RATE 0x00000080
#define MA_PA_STREAM_FIX_CHANNELS 0x00000100
#define MA_PA_STREAM_DONT_MOVE 0x00000200
#define MA_PA_STREAM_VARIABLE_RATE 0x00000400
#define MA_PA_STREAM_PEAK_DETECT 0x00000800
#define MA_PA_STREAM_START_MUTED 0x00001000
#define MA_PA_STREAM_ADJUST_LATENCY 0x00002000
#define MA_PA_STREAM_EARLY_REQUESTS 0x00004000
#define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND 0x00008000
#define MA_PA_STREAM_START_UNMUTED 0x00010000
#define MA_PA_STREAM_FAIL_ON_SUSPEND 0x00020000
#define MA_PA_STREAM_RELATIVE_VOLUME 0x00040000
#define MA_PA_STREAM_PASSTHROUGH 0x00080000
typedef int ma_pa_sink_flags_t;
#define MA_PA_SINK_NOFLAGS 0x00000000
#define MA_PA_SINK_HW_VOLUME_CTRL 0x00000001
#define MA_PA_SINK_LATENCY 0x00000002
#define MA_PA_SINK_HARDWARE 0x00000004
#define MA_PA_SINK_NETWORK 0x00000008
#define MA_PA_SINK_HW_MUTE_CTRL 0x00000010
#define MA_PA_SINK_DECIBEL_VOLUME 0x00000020
#define MA_PA_SINK_FLAT_VOLUME 0x00000040
#define MA_PA_SINK_DYNAMIC_LATENCY 0x00000080
#define MA_PA_SINK_SET_FORMATS 0x00000100
typedef int ma_pa_source_flags_t;
#define MA_PA_SOURCE_NOFLAGS 0x00000000
#define MA_PA_SOURCE_HW_VOLUME_CTRL 0x00000001
#define MA_PA_SOURCE_LATENCY 0x00000002
#define MA_PA_SOURCE_HARDWARE 0x00000004
#define MA_PA_SOURCE_NETWORK 0x00000008
#define MA_PA_SOURCE_HW_MUTE_CTRL 0x00000010
#define MA_PA_SOURCE_DECIBEL_VOLUME 0x00000020
#define MA_PA_SOURCE_DYNAMIC_LATENCY 0x00000040
#define MA_PA_SOURCE_FLAT_VOLUME 0x00000080
typedef int ma_pa_context_state_t;
#define MA_PA_CONTEXT_UNCONNECTED 0
#define MA_PA_CONTEXT_CONNECTING 1
#define MA_PA_CONTEXT_AUTHORIZING 2
#define MA_PA_CONTEXT_SETTING_NAME 3
#define MA_PA_CONTEXT_READY 4
#define MA_PA_CONTEXT_FAILED 5
#define MA_PA_CONTEXT_TERMINATED 6
typedef int ma_pa_stream_state_t;
#define MA_PA_STREAM_UNCONNECTED 0
#define MA_PA_STREAM_CREATING 1
#define MA_PA_STREAM_READY 2
#define MA_PA_STREAM_FAILED 3
#define MA_PA_STREAM_TERMINATED 4
typedef int ma_pa_operation_state_t;
#define MA_PA_OPERATION_RUNNING 0
#define MA_PA_OPERATION_DONE 1
#define MA_PA_OPERATION_CANCELLED 2
typedef int ma_pa_sink_state_t;
#define MA_PA_SINK_INVALID_STATE -1
#define MA_PA_SINK_RUNNING 0
#define MA_PA_SINK_IDLE 1
#define MA_PA_SINK_SUSPENDED 2
typedef int ma_pa_source_state_t;
#define MA_PA_SOURCE_INVALID_STATE -1
#define MA_PA_SOURCE_RUNNING 0
#define MA_PA_SOURCE_IDLE 1
#define MA_PA_SOURCE_SUSPENDED 2
typedef int ma_pa_seek_mode_t;
#define MA_PA_SEEK_RELATIVE 0
#define MA_PA_SEEK_ABSOLUTE 1
#define MA_PA_SEEK_RELATIVE_ON_READ 2
#define MA_PA_SEEK_RELATIVE_END 3
typedef int ma_pa_channel_position_t;
#define MA_PA_CHANNEL_POSITION_INVALID -1
#define MA_PA_CHANNEL_POSITION_MONO 0
#define MA_PA_CHANNEL_POSITION_FRONT_LEFT 1
#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT 2
#define MA_PA_CHANNEL_POSITION_FRONT_CENTER 3
#define MA_PA_CHANNEL_POSITION_REAR_CENTER 4
#define MA_PA_CHANNEL_POSITION_REAR_LEFT 5
#define MA_PA_CHANNEL_POSITION_REAR_RIGHT 6
#define MA_PA_CHANNEL_POSITION_LFE 7
#define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER 8
#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER 9
#define MA_PA_CHANNEL_POSITION_SIDE_LEFT 10
#define MA_PA_CHANNEL_POSITION_SIDE_RIGHT 11
#define MA_PA_CHANNEL_POSITION_AUX0 12
#define MA_PA_CHANNEL_POSITION_AUX1 13
#define MA_PA_CHANNEL_POSITION_AUX2 14
#define MA_PA_CHANNEL_POSITION_AUX3 15
#define MA_PA_CHANNEL_POSITION_AUX4 16
#define MA_PA_CHANNEL_POSITION_AUX5 17
#define MA_PA_CHANNEL_POSITION_AUX6 18
#define MA_PA_CHANNEL_POSITION_AUX7 19
#define MA_PA_CHANNEL_POSITION_AUX8 20
#define MA_PA_CHANNEL_POSITION_AUX9 21
#define MA_PA_CHANNEL_POSITION_AUX10 22
#define MA_PA_CHANNEL_POSITION_AUX11 23
#define MA_PA_CHANNEL_POSITION_AUX12 24
#define MA_PA_CHANNEL_POSITION_AUX13 25
#define MA_PA_CHANNEL_POSITION_AUX14 26
#define MA_PA_CHANNEL_POSITION_AUX15 27
#define MA_PA_CHANNEL_POSITION_AUX16 28
#define MA_PA_CHANNEL_POSITION_AUX17 29
#define MA_PA_CHANNEL_POSITION_AUX18 30
#define MA_PA_CHANNEL_POSITION_AUX19 31
#define MA_PA_CHANNEL_POSITION_AUX20 32
#define MA_PA_CHANNEL_POSITION_AUX21 33
#define MA_PA_CHANNEL_POSITION_AUX22 34
#define MA_PA_CHANNEL_POSITION_AUX23 35
#define MA_PA_CHANNEL_POSITION_AUX24 36
#define MA_PA_CHANNEL_POSITION_AUX25 37
#define MA_PA_CHANNEL_POSITION_AUX26 38
#define MA_PA_CHANNEL_POSITION_AUX27 39
#define MA_PA_CHANNEL_POSITION_AUX28 40
#define MA_PA_CHANNEL_POSITION_AUX29 41
#define MA_PA_CHANNEL_POSITION_AUX30 42
#define MA_PA_CHANNEL_POSITION_AUX31 43
#define MA_PA_CHANNEL_POSITION_TOP_CENTER 44
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT 45
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT 46
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER 47
#define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT 48
#define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT 49
#define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER 50
#define MA_PA_CHANNEL_POSITION_LEFT MA_PA_CHANNEL_POSITION_FRONT_LEFT
#define MA_PA_CHANNEL_POSITION_RIGHT MA_PA_CHANNEL_POSITION_FRONT_RIGHT
#define MA_PA_CHANNEL_POSITION_CENTER MA_PA_CHANNEL_POSITION_FRONT_CENTER
#define MA_PA_CHANNEL_POSITION_SUBWOOFER MA_PA_CHANNEL_POSITION_LFE
typedef int ma_pa_channel_map_def_t;
#define MA_PA_CHANNEL_MAP_AIFF 0
#define MA_PA_CHANNEL_MAP_ALSA 1
#define MA_PA_CHANNEL_MAP_AUX 2
#define MA_PA_CHANNEL_MAP_WAVEEX 3
#define MA_PA_CHANNEL_MAP_OSS 4
#define MA_PA_CHANNEL_MAP_DEFAULT MA_PA_CHANNEL_MAP_AIFF
typedef int ma_pa_sample_format_t;
#define MA_PA_SAMPLE_INVALID -1
#define MA_PA_SAMPLE_U8 0
#define MA_PA_SAMPLE_ALAW 1
#define MA_PA_SAMPLE_ULAW 2
#define MA_PA_SAMPLE_S16LE 3
#define MA_PA_SAMPLE_S16BE 4
#define MA_PA_SAMPLE_FLOAT32LE 5
#define MA_PA_SAMPLE_FLOAT32BE 6
#define MA_PA_SAMPLE_S32LE 7
#define MA_PA_SAMPLE_S32BE 8
#define MA_PA_SAMPLE_S24LE 9
#define MA_PA_SAMPLE_S24BE 10
#define MA_PA_SAMPLE_S24_32LE 11
#define MA_PA_SAMPLE_S24_32BE 12
typedef struct ma_pa_mainloop ma_pa_mainloop;
typedef struct ma_pa_threaded_mainloop ma_pa_threaded_mainloop;
typedef struct ma_pa_mainloop_api ma_pa_mainloop_api;
typedef struct ma_pa_context ma_pa_context;
typedef struct ma_pa_operation ma_pa_operation;
typedef struct ma_pa_stream ma_pa_stream;
typedef struct ma_pa_spawn_api ma_pa_spawn_api;
typedef struct
{
M3 maxlength;
M3 tlength;
M3 prebuf;
M3 minreq;
M3 fragsize;
} ma_pa_buffer_attr;
typedef struct
{
ma_uint8 Mh;
ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX];
} ma_pa_channel_map;
typedef struct
{
ma_uint8 Mh;
M3 values[MA_PA_CHANNELS_MAX];
} ma_pa_cvolume;
typedef struct
{
ma_pa_sample_format_t format;
M3 rate;
ma_uint8 Mh;
} ma_pa_sample_spec;
typedef struct
{
const char*name;
M3 index;
const char*description;
ma_pa_sample_spec sample_spec;
ma_pa_channel_map channel_map;
M3 owner_module;
ma_pa_cvolume volume;
int mute;
M3 monitor_source;
const char*monitor_source_name;
M6 latency;
const char*driver;
ma_pa_sink_flags_t flags;
Mv*proplist;
M6 configured_latency;
M3 base_volume;
ma_pa_sink_state_t state;
M3 n_volume_steps;
M3 card;
M3 n_ports;
Mv**ports;
Mv*active_port;
ma_uint8 n_formats;
Mv**formats;
} ma_pa_sink_info;
typedef struct
{
const char*name;
M3 index;
const char*description;
ma_pa_sample_spec sample_spec;
ma_pa_channel_map channel_map;
M3 owner_module;
ma_pa_cvolume volume;
int mute;
M3 monitor_of_sink;
const char*monitor_of_sink_name;
M6 latency;
const char*driver;
ma_pa_source_flags_t flags;
Mv*proplist;
M6 configured_latency;
M3 base_volume;
ma_pa_source_state_t state;
M3 n_volume_steps;
M3 card;
M3 n_ports;
Mv**ports;
Mv*active_port;
ma_uint8 n_formats;
Mv**formats;
} ma_pa_source_info;
typedef Mv (*ma_pa_context_notify_cb_t)(ma_pa_context*c,Mv*userdata);
typedef Mv (*ma_pa_sink_info_cb_t) (ma_pa_context*c,const ma_pa_sink_info*i,int eol,Mv*userdata);
typedef Mv (*ma_pa_source_info_cb_t) (ma_pa_context*c,const ma_pa_source_info*i,int eol,Mv*userdata);
typedef Mv (*ma_pa_stream_success_cb_t)(ma_pa_stream*s,int success,Mv*userdata);
typedef Mv (*ma_pa_stream_request_cb_t)(ma_pa_stream*s,size_t nbytes,Mv*userdata);
typedef Mv (*ma_pa_stream_notify_cb_t) (ma_pa_stream*s,Mv*userdata);
typedef Mv (*ma_pa_free_cb_t) (Mv*p);
#endif
typedef ma_pa_mainloop*(*ma_pa_mainloop_new_proc) (Mv);
typedef Mv (*ma_pa_mainloop_free_proc) (ma_pa_mainloop*m);
typedef Mv (*ma_pa_mainloop_quit_proc) (ma_pa_mainloop*m,int retval);
typedef ma_pa_mainloop_api*(*ma_pa_mainloop_get_api_proc) (ma_pa_mainloop*m);
typedef int (*ma_pa_mainloop_iterate_proc) (ma_pa_mainloop*m,int block,int*retval);
typedef Mv (*ma_pa_mainloop_wakeup_proc) (ma_pa_mainloop*m);
typedef ma_pa_threaded_mainloop*(*ma_pa_threaded_mainloop_new_proc) (Mv);
typedef Mv (*ma_pa_threaded_mainloop_free_proc) (ma_pa_threaded_mainloop*m);
typedef int (*ma_pa_threaded_mainloop_start_proc) (ma_pa_threaded_mainloop*m);
typedef Mv (*ma_pa_threaded_mainloop_stop_proc) (ma_pa_threaded_mainloop*m);
typedef Mv (*ma_pa_threaded_mainloop_lock_proc) (ma_pa_threaded_mainloop*m);
typedef Mv (*ma_pa_threaded_mainloop_unlock_proc) (ma_pa_threaded_mainloop*m);
typedef Mv (*ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop*m);
typedef Mv (*ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop*m,int wait_for_accept);
typedef Mv (*ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop*m);
typedef int (*ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop*m);
typedef ma_pa_mainloop_api*(*ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop*m);
typedef int (*ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop*m);
typedef Mv (*ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop*m,const char*name);
typedef ma_pa_context*(*ma_pa_context_new_proc) (ma_pa_mainloop_api*mainloop,const char*name);
typedef Mv (*ma_pa_context_unref_proc) (ma_pa_context*c);
typedef int (*ma_pa_context_connect_proc) (ma_pa_context*c,const char*server,ma_pa_context_flags_t flags,const ma_pa_spawn_api*api);
typedef Mv (*ma_pa_context_disconnect_proc) (ma_pa_context*c);
typedef Mv (*ma_pa_context_set_state_callback_proc) (ma_pa_context*c,ma_pa_context_notify_cb_t cb,Mv*userdata);
typedef ma_pa_context_state_t (*ma_pa_context_get_state_proc) (ma_pa_context*c);
typedef ma_pa_operation*(*ma_pa_context_get_sink_info_list_proc) (ma_pa_context*c,ma_pa_sink_info_cb_t cb,Mv*userdata);
typedef ma_pa_operation*(*ma_pa_context_get_source_info_list_proc) (ma_pa_context*c,ma_pa_source_info_cb_t cb,Mv*userdata);
typedef ma_pa_operation*(*ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context*c,const char*name,ma_pa_sink_info_cb_t cb,Mv*userdata);
typedef ma_pa_operation*(*ma_pa_context_get_source_info_by_name_proc)(ma_pa_context*c,const char*name,ma_pa_source_info_cb_t cb,Mv*userdata);
typedef Mv (*ma_pa_operation_unref_proc) (ma_pa_operation*o);
typedef ma_pa_operation_state_t (*ma_pa_operation_get_state_proc) (ma_pa_operation*o);
typedef ma_pa_channel_map*(*ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map*m,unsigned Mh,ma_pa_channel_map_def_t def);
typedef int (*ma_pa_channel_map_valid_proc) (const ma_pa_channel_map*m);
typedef int (*ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map*m,const ma_pa_sample_spec*ss);
typedef ma_pa_stream*(*ma_pa_stream_new_proc) (ma_pa_context*c,const char*name,const ma_pa_sample_spec*ss,const ma_pa_channel_map*map);
typedef Mv (*ma_pa_stream_unref_proc) (ma_pa_stream*s);
typedef int (*ma_pa_stream_connect_playback_proc) (ma_pa_stream*s,const char*dev,const ma_pa_buffer_attr*attr,ma_pa_stream_flags_t flags,const ma_pa_cvolume*volume,ma_pa_stream*sync_stream);
typedef int (*ma_pa_stream_connect_record_proc) (ma_pa_stream*s,const char*dev,const ma_pa_buffer_attr*attr,ma_pa_stream_flags_t flags);
typedef int (*ma_pa_stream_disconnect_proc) (ma_pa_stream*s);
typedef ma_pa_stream_state_t (*ma_pa_stream_get_state_proc) (ma_pa_stream*s);
typedef const ma_pa_sample_spec*(*ma_pa_stream_get_sample_spec_proc) (ma_pa_stream*s);
typedef const ma_pa_channel_map*(*ma_pa_stream_get_channel_map_proc) (ma_pa_stream*s);
typedef const ma_pa_buffer_attr*(*ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream*s);
typedef ma_pa_operation*(*ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream*s,const ma_pa_buffer_attr*attr,ma_pa_stream_success_cb_t cb,Mv*userdata);
typedef const char*(*ma_pa_stream_get_device_name_proc) (ma_pa_stream*s);
typedef Mv (*ma_pa_stream_set_write_callback_proc) (ma_pa_stream*s,ma_pa_stream_request_cb_t cb,Mv*userdata);
typedef Mv (*ma_pa_stream_set_read_callback_proc) (ma_pa_stream*s,ma_pa_stream_request_cb_t cb,Mv*userdata);
typedef Mv (*ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream*s,ma_pa_stream_notify_cb_t cb,Mv*userdata);
typedef Mv (*ma_pa_stream_set_moved_callback_proc) (ma_pa_stream*s,ma_pa_stream_notify_cb_t cb,Mv*userdata);
typedef int (*ma_pa_stream_is_suspended_proc) (const ma_pa_stream*s);
typedef ma_pa_operation*(*ma_pa_stream_flush_proc) (ma_pa_stream*s,ma_pa_stream_success_cb_t cb,Mv*userdata);
typedef ma_pa_operation*(*ma_pa_stream_drain_proc) (ma_pa_stream*s,ma_pa_stream_success_cb_t cb,Mv*userdata);
typedef int (*ma_pa_stream_is_corked_proc) (ma_pa_stream*s);
typedef ma_pa_operation*(*ma_pa_stream_cork_proc) (ma_pa_stream*s,int b,ma_pa_stream_success_cb_t cb,Mv*userdata);
typedef ma_pa_operation*(*ma_pa_stream_trigger_proc) (ma_pa_stream*s,ma_pa_stream_success_cb_t cb,Mv*userdata);
typedef int (*ma_pa_stream_begin_write_proc) (ma_pa_stream*s,Mv**data,size_t*nbytes);
typedef int (*ma_pa_stream_write_proc) (ma_pa_stream*s,const Mv*data,size_t nbytes,ma_pa_free_cb_t free_cb,int64_t offset,ma_pa_seek_mode_t seek);
typedef int (*ma_pa_stream_peek_proc) (ma_pa_stream*s,const Mv**data,size_t*nbytes);
typedef int (*ma_pa_stream_drop_proc) (ma_pa_stream*s);
typedef size_t (*ma_pa_stream_writable_size_proc) (ma_pa_stream*s);
typedef size_t (*ma_pa_stream_readable_size_proc) (ma_pa_stream*s);
typedef struct
{
M3 count;
M3 capacity;
ma_device_info*pInfo;
} ma_pulse_device_enum_data;
static Me ma_result_from_pulse(int Mf)
{
if (Mf<0) {
Mr MA_ERROR;
}
switch (Mf) {
case MA_PA_OK:Mr Ms;
case MA_PA_ERR_ACCESS:Mr MA_ACCESS_DENIED;
case MA_PA_ERR_INVALID:Mr MA_INVALID_ARGS;
case MA_PA_ERR_NOENTITY:Mr MA_NO_DEVICE;
default:Mr MA_ERROR;
}
}
#if 0
static ma_pa_sample_format_t ma_format_to_pulse(ma_format format)
{
if (ma_is_little_endian()) {
switch (format) {
case ma_format_s16:Mr MA_PA_SAMPLE_S16LE;
case ma_format_s24:Mr MA_PA_SAMPLE_S24LE;
case ma_format_s32:Mr MA_PA_SAMPLE_S32LE;
case ma_format_f32:Mr MA_PA_SAMPLE_FLOAT32LE;
default:break;
}
} else {
switch (format) {
case ma_format_s16:Mr MA_PA_SAMPLE_S16BE;
case ma_format_s24:Mr MA_PA_SAMPLE_S24BE;
case ma_format_s32:Mr MA_PA_SAMPLE_S32BE;
case ma_format_f32:Mr MA_PA_SAMPLE_FLOAT32BE;
default:break;
}
}
switch (format) {
case ma_format_u8:Mr MA_PA_SAMPLE_U8;
default:Mr MA_PA_SAMPLE_INVALID;
}
}
#endif
static ma_format ma_format_from_pulse(ma_pa_sample_format_t format)
{
if (ma_is_little_endian()) {
switch (format) {
case MA_PA_SAMPLE_S16LE:Mr ma_format_s16;
case MA_PA_SAMPLE_S24LE:Mr ma_format_s24;
case MA_PA_SAMPLE_S32LE:Mr ma_format_s32;
case MA_PA_SAMPLE_FLOAT32LE:Mr ma_format_f32;
default:break;
}
} else {
switch (format) {
case MA_PA_SAMPLE_S16BE:Mr ma_format_s16;
case MA_PA_SAMPLE_S24BE:Mr ma_format_s24;
case MA_PA_SAMPLE_S32BE:Mr ma_format_s32;
case MA_PA_SAMPLE_FLOAT32BE:Mr ma_format_f32;
default:break;
}
}
switch (format) {
case MA_PA_SAMPLE_U8:Mr ma_format_u8;
default:Mr ma_format_unknown;
}
}
static ma_channel ma_channel_position_from_pulse(ma_pa_channel_position_t position)
{
switch (position)
{
case MA_PA_CHANNEL_POSITION_INVALID:Mr MA_CHANNEL_NONE;
case MA_PA_CHANNEL_POSITION_MONO:Mr MA_CHANNEL_MONO;
case MA_PA_CHANNEL_POSITION_FRONT_LEFT:Mr MA_CHANNEL_FRONT_LEFT;
case MA_PA_CHANNEL_POSITION_FRONT_RIGHT:Mr MA_CHANNEL_FRONT_RIGHT;
case MA_PA_CHANNEL_POSITION_FRONT_CENTER:Mr MA_CHANNEL_FRONT_CENTER;
case MA_PA_CHANNEL_POSITION_REAR_CENTER:Mr MA_CHANNEL_BACK_CENTER;
case MA_PA_CHANNEL_POSITION_REAR_LEFT:Mr MA_CHANNEL_BACK_LEFT;
case MA_PA_CHANNEL_POSITION_REAR_RIGHT:Mr MA_CHANNEL_BACK_RIGHT;
case MA_PA_CHANNEL_POSITION_LFE:Mr MA_CHANNEL_LFE;
case MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:Mr MA_CHANNEL_FRONT_LEFT_CENTER;
case MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:Mr MA_CHANNEL_FRONT_RIGHT_CENTER;
case MA_PA_CHANNEL_POSITION_SIDE_LEFT:Mr MA_CHANNEL_SIDE_LEFT;
case MA_PA_CHANNEL_POSITION_SIDE_RIGHT:Mr MA_CHANNEL_SIDE_RIGHT;
case MA_PA_CHANNEL_POSITION_AUX0:Mr MA_CHANNEL_AUX_0;
case MA_PA_CHANNEL_POSITION_AUX1:Mr MA_CHANNEL_AUX_1;
case MA_PA_CHANNEL_POSITION_AUX2:Mr MA_CHANNEL_AUX_2;
case MA_PA_CHANNEL_POSITION_AUX3:Mr MA_CHANNEL_AUX_3;
case MA_PA_CHANNEL_POSITION_AUX4:Mr MA_CHANNEL_AUX_4;
case MA_PA_CHANNEL_POSITION_AUX5:Mr MA_CHANNEL_AUX_5;
case MA_PA_CHANNEL_POSITION_AUX6:Mr MA_CHANNEL_AUX_6;
case MA_PA_CHANNEL_POSITION_AUX7:Mr MA_CHANNEL_AUX_7;
case MA_PA_CHANNEL_POSITION_AUX8:Mr MA_CHANNEL_AUX_8;
case MA_PA_CHANNEL_POSITION_AUX9:Mr MA_CHANNEL_AUX_9;
case MA_PA_CHANNEL_POSITION_AUX10:Mr MA_CHANNEL_AUX_10;
case MA_PA_CHANNEL_POSITION_AUX11:Mr MA_CHANNEL_AUX_11;
case MA_PA_CHANNEL_POSITION_AUX12:Mr MA_CHANNEL_AUX_12;
case MA_PA_CHANNEL_POSITION_AUX13:Mr MA_CHANNEL_AUX_13;
case MA_PA_CHANNEL_POSITION_AUX14:Mr MA_CHANNEL_AUX_14;
case MA_PA_CHANNEL_POSITION_AUX15:Mr MA_CHANNEL_AUX_15;
case MA_PA_CHANNEL_POSITION_AUX16:Mr MA_CHANNEL_AUX_16;
case MA_PA_CHANNEL_POSITION_AUX17:Mr MA_CHANNEL_AUX_17;
case MA_PA_CHANNEL_POSITION_AUX18:Mr MA_CHANNEL_AUX_18;
case MA_PA_CHANNEL_POSITION_AUX19:Mr MA_CHANNEL_AUX_19;
case MA_PA_CHANNEL_POSITION_AUX20:Mr MA_CHANNEL_AUX_20;
case MA_PA_CHANNEL_POSITION_AUX21:Mr MA_CHANNEL_AUX_21;
case MA_PA_CHANNEL_POSITION_AUX22:Mr MA_CHANNEL_AUX_22;
case MA_PA_CHANNEL_POSITION_AUX23:Mr MA_CHANNEL_AUX_23;
case MA_PA_CHANNEL_POSITION_AUX24:Mr MA_CHANNEL_AUX_24;
case MA_PA_CHANNEL_POSITION_AUX25:Mr MA_CHANNEL_AUX_25;
case MA_PA_CHANNEL_POSITION_AUX26:Mr MA_CHANNEL_AUX_26;
case MA_PA_CHANNEL_POSITION_AUX27:Mr MA_CHANNEL_AUX_27;
case MA_PA_CHANNEL_POSITION_AUX28:Mr MA_CHANNEL_AUX_28;
case MA_PA_CHANNEL_POSITION_AUX29:Mr MA_CHANNEL_AUX_29;
case MA_PA_CHANNEL_POSITION_AUX30:Mr MA_CHANNEL_AUX_30;
case MA_PA_CHANNEL_POSITION_AUX31:Mr MA_CHANNEL_AUX_31;
case MA_PA_CHANNEL_POSITION_TOP_CENTER:Mr MA_CHANNEL_TOP_CENTER;
case MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT:Mr MA_CHANNEL_TOP_FRONT_LEFT;
case MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:Mr MA_CHANNEL_TOP_FRONT_RIGHT;
case MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER:Mr MA_CHANNEL_TOP_FRONT_CENTER;
case MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT:Mr MA_CHANNEL_TOP_BACK_LEFT;
case MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT:Mr MA_CHANNEL_TOP_BACK_RIGHT;
case MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER:Mr MA_CHANNEL_TOP_BACK_CENTER;
default:Mr MA_CHANNEL_NONE;
}
}
#if 0
static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position)
{
switch (position)
{
case MA_CHANNEL_NONE:Mr MA_PA_CHANNEL_POSITION_INVALID;
case MA_CHANNEL_FRONT_LEFT:Mr MA_PA_CHANNEL_POSITION_FRONT_LEFT;
case MA_CHANNEL_FRONT_RIGHT:Mr MA_PA_CHANNEL_POSITION_FRONT_RIGHT;
case MA_CHANNEL_FRONT_CENTER:Mr MA_PA_CHANNEL_POSITION_FRONT_CENTER;
case MA_CHANNEL_LFE:Mr MA_PA_CHANNEL_POSITION_LFE;
case MA_CHANNEL_BACK_LEFT:Mr MA_PA_CHANNEL_POSITION_REAR_LEFT;
case MA_CHANNEL_BACK_RIGHT:Mr MA_PA_CHANNEL_POSITION_REAR_RIGHT;
case MA_CHANNEL_FRONT_LEFT_CENTER:Mr MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
case MA_CHANNEL_FRONT_RIGHT_CENTER:Mr MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
case MA_CHANNEL_BACK_CENTER:Mr MA_PA_CHANNEL_POSITION_REAR_CENTER;
case MA_CHANNEL_SIDE_LEFT:Mr MA_PA_CHANNEL_POSITION_SIDE_LEFT;
case MA_CHANNEL_SIDE_RIGHT:Mr MA_PA_CHANNEL_POSITION_SIDE_RIGHT;
case MA_CHANNEL_TOP_CENTER:Mr MA_PA_CHANNEL_POSITION_TOP_CENTER;
case MA_CHANNEL_TOP_FRONT_LEFT:Mr MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
case MA_CHANNEL_TOP_FRONT_CENTER:Mr MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
case MA_CHANNEL_TOP_FRONT_RIGHT:Mr MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
case MA_CHANNEL_TOP_BACK_LEFT:Mr MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT;
case MA_CHANNEL_TOP_BACK_CENTER:Mr MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER;
case MA_CHANNEL_TOP_BACK_RIGHT:Mr MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
case MA_CHANNEL_19:Mr MA_PA_CHANNEL_POSITION_AUX18;
case MA_CHANNEL_20:Mr MA_PA_CHANNEL_POSITION_AUX19;
case MA_CHANNEL_21:Mr MA_PA_CHANNEL_POSITION_AUX20;
case MA_CHANNEL_22:Mr MA_PA_CHANNEL_POSITION_AUX21;
case MA_CHANNEL_23:Mr MA_PA_CHANNEL_POSITION_AUX22;
case MA_CHANNEL_24:Mr MA_PA_CHANNEL_POSITION_AUX23;
case MA_CHANNEL_25:Mr MA_PA_CHANNEL_POSITION_AUX24;
case MA_CHANNEL_26:Mr MA_PA_CHANNEL_POSITION_AUX25;
case MA_CHANNEL_27:Mr MA_PA_CHANNEL_POSITION_AUX26;
case MA_CHANNEL_28:Mr MA_PA_CHANNEL_POSITION_AUX27;
case MA_CHANNEL_29:Mr MA_PA_CHANNEL_POSITION_AUX28;
case MA_CHANNEL_30:Mr MA_PA_CHANNEL_POSITION_AUX29;
case MA_CHANNEL_31:Mr MA_PA_CHANNEL_POSITION_AUX30;
case MA_CHANNEL_32:Mr MA_PA_CHANNEL_POSITION_AUX31;
default:Mr (ma_pa_channel_position_t)position;
}
}
#endif
static Me ma_wait_for_operation__pulse(ma_context*Mc,ma_ptr pMainLoop,ma_pa_operation*pOP)
{
int resultPA;
ma_pa_operation_state_t state;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pOP !=NULL);
for (;;) {
state=((ma_pa_operation_get_state_proc)Mc->pulse.pa_operation_get_state)(pOP);
if (state !=MA_PA_OPERATION_RUNNING) {
break;
}
resultPA=((ma_pa_mainloop_iterate_proc)Mc->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop,1,NULL);
if (resultPA<0) {
Mr ma_result_from_pulse(resultPA);
}
}
Mr Ms;
}
static Me ma_wait_for_operation_and_unref__pulse(ma_context*Mc,ma_ptr pMainLoop,ma_pa_operation*pOP)
{
Me Mf;
if (pOP==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_wait_for_operation__pulse(Mc,pMainLoop,pOP);
((ma_pa_operation_unref_proc)Mc->pulse.pa_operation_unref)(pOP);
Mr Mf;
}
static Me ma_wait_for_pa_context_to_connect__pulse(ma_context*Mc,ma_ptr pMainLoop,ma_ptr pPulseContext)
{
int resultPA;
ma_pa_context_state_t state;
for (;;) {
state=((ma_pa_context_get_state_proc)Mc->pulse.pa_context_get_state)((ma_pa_context*)pPulseContext);
if (state==MA_PA_CONTEXT_READY) {
break;
}
if (state==MA_PA_CONTEXT_FAILED||state==MA_PA_CONTEXT_TERMINATED) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.");
Mr MA_ERROR;
}
resultPA=((ma_pa_mainloop_iterate_proc)Mc->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop,1,NULL);
if (resultPA<0) {
Mr ma_result_from_pulse(resultPA);
}
}
Mr Ms;
}
static Me ma_wait_for_pa_stream_to_connect__pulse(ma_context*Mc,ma_ptr pMainLoop,ma_ptr pStream)
{
int resultPA;
ma_pa_stream_state_t state;
for (;;) {
state=((ma_pa_stream_get_state_proc)Mc->pulse.pa_stream_get_state)((ma_pa_stream*)pStream);
if (state==MA_PA_STREAM_READY) {
break;
}
if (state==MA_PA_STREAM_FAILED||state==MA_PA_STREAM_TERMINATED) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream.");
Mr MA_ERROR;
}
resultPA=((ma_pa_mainloop_iterate_proc)Mc->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop,1,NULL);
if (resultPA<0) {
Mr ma_result_from_pulse(resultPA);
}
}
Mr Ms;
}
static Me ma_init_pa_mainloop_and_pa_context__pulse(ma_context*Mc,const char*pApplicationName,const char*pServerName,ma_bool32 tryAutoSpawn,ma_ptr*ppMainLoop,ma_ptr*ppPulseContext)
{
Me Mf;
ma_ptr pMainLoop;
ma_ptr pPulseContext;
MA_ASSERT(ppMainLoop !=NULL);
MA_ASSERT(ppPulseContext !=NULL);
pMainLoop=((ma_pa_mainloop_new_proc)Mc->pulse.pa_mainloop_new)();
if (pMainLoop==NULL) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop.");
Mr MA_FAILED_TO_INIT_BACKEND;
}
pPulseContext=((ma_pa_context_new_proc)Mc->pulse.pa_context_new)(((ma_pa_mainloop_get_api_proc)Mc->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pMainLoop),pApplicationName);
if (pPulseContext==NULL) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context.");
((ma_pa_mainloop_free_proc)Mc->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop));
Mr MA_FAILED_TO_INIT_BACKEND;
}
Mf=ma_result_from_pulse(((ma_pa_context_connect_proc)Mc->pulse.pa_context_connect)((ma_pa_context*)pPulseContext,pServerName,(tryAutoSpawn)?0:MA_PA_CONTEXT_NOAUTOSPAWN,NULL));
if (Mf !=Ms) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.");
((ma_pa_mainloop_free_proc)Mc->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop));
Mr Mf;
}
Mf=ma_wait_for_pa_context_to_connect__pulse(Mc,pMainLoop,pPulseContext);
if (Mf !=Ms) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[PulseAudio] Waiting for connection failed.");
((ma_pa_mainloop_free_proc)Mc->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop));
Mr Mf;
}
*ppMainLoop=pMainLoop;
*ppPulseContext=pPulseContext;
Mr Ms;
}
static Mv ma_device_sink_info_callback(ma_pa_context*pPulseContext,const ma_pa_sink_info*pInfo,int endOfList,Mv*pUserData)
{
ma_pa_sink_info*pInfoOut;
if (endOfList>0) {
Mr;
}
if (pInfo==NULL) {
Mr;
}
pInfoOut=(ma_pa_sink_info*)pUserData;
MA_ASSERT(pInfoOut !=NULL);
*pInfoOut=*pInfo;
(Mv)pPulseContext;
}
static Mv ma_device_source_info_callback(ma_pa_context*pPulseContext,const ma_pa_source_info*pInfo,int endOfList,Mv*pUserData)
{
ma_pa_source_info*pInfoOut;
if (endOfList>0) {
Mr;
}
if (pInfo==NULL) {
Mr;
}
pInfoOut=(ma_pa_source_info*)pUserData;
MA_ASSERT(pInfoOut !=NULL);
*pInfoOut=*pInfo;
(Mv)pPulseContext;
}
#if 0
static Mv ma_device_sink_name_callback(ma_pa_context*pPulseContext,const ma_pa_sink_info*pInfo,int endOfList,Mv*pUserData)
{
ma_device*Md;
if (endOfList>0) {
Mr;
}
Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
ma_strncpy_s(Md->playback.name,sizeof(Md->playback.name),pInfo->description,(size_t)-1);
(Mv)pPulseContext;
}
static Mv ma_device_source_name_callback(ma_pa_context*pPulseContext,const ma_pa_source_info*pInfo,int endOfList,Mv*pUserData)
{
ma_device*Md;
if (endOfList>0) {
Mr;
}
Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
ma_strncpy_s(Md->capture.name,sizeof(Md->capture.name),pInfo->description,(size_t)-1);
(Mv)pPulseContext;
}
#endif
static Me ma_context_get_sink_info__pulse(ma_context*Mc,const char*pDeviceName,ma_pa_sink_info*pSinkInfo)
{
ma_pa_operation*pOP;
pOP=((ma_pa_context_get_sink_info_by_name_proc)Mc->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)Mc->pulse.pPulseContext,pDeviceName,ma_device_sink_info_callback,pSinkInfo);
if (pOP==NULL) {
Mr MA_ERROR;
}
Mr ma_wait_for_operation_and_unref__pulse(Mc,Mc->pulse.pMainLoop,pOP);
}
static Me ma_context_get_source_info__pulse(ma_context*Mc,const char*pDeviceName,ma_pa_source_info*pSourceInfo)
{
ma_pa_operation*pOP;
pOP=((ma_pa_context_get_source_info_by_name_proc)Mc->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)Mc->pulse.pPulseContext,pDeviceName,ma_device_source_info_callback,pSourceInfo);
if (pOP==NULL) {
Mr MA_ERROR;
}
Mr ma_wait_for_operation_and_unref__pulse(Mc,Mc->pulse.pMainLoop,pOP);
}
static Me ma_context_get_default_device_index__pulse(ma_context*Mc,ma_device_type deviceType,M3*pIndex)
{
Me Mf;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pIndex !=NULL);
if (pIndex !=NULL) {
*pIndex=(M3)-1;
}
if (deviceType==Mt) {
ma_pa_sink_info sinkInfo;
Mf=ma_context_get_sink_info__pulse(Mc,NULL,&sinkInfo);
if (Mf !=Ms) {
Mr Mf;
}
if (pIndex !=NULL) {
*pIndex=sinkInfo.index;
}
}
if (deviceType==ma_device_type_capture) {
ma_pa_source_info sourceInfo;
Mf=ma_context_get_source_info__pulse(Mc,NULL,&sourceInfo);
if (Mf !=Ms) {
Mr Mf;
}
if (pIndex !=NULL) {
*pIndex=sourceInfo.index;
}
}
Mr Ms;
}
typedef struct
{
ma_context*Mc;
ma_enum_devices_callback_proc callback;
Mv*pUserData;
ma_bool32 isTerminated;
M3 defaultDeviceIndexPlayback;
M3 defaultDeviceIndexCapture;
} ma_context_enumerate_devices_callback_data__pulse;
static Mv ma_context_enumerate_devices_sink_callback__pulse(ma_pa_context*pPulseContext,const ma_pa_sink_info*pSinkInfo,int endOfList,Mv*pUserData)
{
ma_context_enumerate_devices_callback_data__pulse*pData=(ma_context_enumerate_devices_callback_data__pulse*)pUserData;
ma_device_info deviceInfo;
MA_ASSERT(pData !=NULL);
if (endOfList||pData->isTerminated) {
Mr;
}
MA_ZERO_OBJECT(&deviceInfo);
if (pSinkInfo->name !=NULL) {
ma_strncpy_s(deviceInfo.id.pulse,sizeof(deviceInfo.id.pulse),pSinkInfo->name,(size_t)-1);
}
if (pSinkInfo->description !=NULL) {
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),pSinkInfo->description,(size_t)-1);
}
if (pSinkInfo->index==pData->defaultDeviceIndexPlayback) {
deviceInfo.isDefault=MA_TRUE;
}
pData->isTerminated=!pData->callback(pData->Mc,Mt,&deviceInfo,pData->pUserData);
(Mv)pPulseContext;
}
static Mv ma_context_enumerate_devices_source_callback__pulse(ma_pa_context*pPulseContext,const ma_pa_source_info*pSourceInfo,int endOfList,Mv*pUserData)
{
ma_context_enumerate_devices_callback_data__pulse*pData=(ma_context_enumerate_devices_callback_data__pulse*)pUserData;
ma_device_info deviceInfo;
MA_ASSERT(pData !=NULL);
if (endOfList||pData->isTerminated) {
Mr;
}
MA_ZERO_OBJECT(&deviceInfo);
if (pSourceInfo->name !=NULL) {
ma_strncpy_s(deviceInfo.id.pulse,sizeof(deviceInfo.id.pulse),pSourceInfo->name,(size_t)-1);
}
if (pSourceInfo->description !=NULL) {
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),pSourceInfo->description,(size_t)-1);
}
if (pSourceInfo->index==pData->defaultDeviceIndexCapture) {
deviceInfo.isDefault=MA_TRUE;
}
pData->isTerminated=!pData->callback(pData->Mc,ma_device_type_capture,&deviceInfo,pData->pUserData);
(Mv)pPulseContext;
}
static Me ma_context_enumerate_devices__pulse(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
Me Mf=Ms;
ma_context_enumerate_devices_callback_data__pulse callbackData;
ma_pa_operation*pOP=NULL;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
callbackData.Mc=Mc;
callbackData.callback=callback;
callbackData.pUserData=pUserData;
callbackData.isTerminated=MA_FALSE;
callbackData.defaultDeviceIndexPlayback=(M3)-1;
callbackData.defaultDeviceIndexCapture=(M3)-1;
ma_context_get_default_device_index__pulse(Mc,Mt,&callbackData.defaultDeviceIndexPlayback);
ma_context_get_default_device_index__pulse(Mc,ma_device_type_capture,&callbackData.defaultDeviceIndexCapture);
if (!callbackData.isTerminated) {
pOP=((ma_pa_context_get_sink_info_list_proc)Mc->pulse.pa_context_get_sink_info_list)((ma_pa_context*)(Mc->pulse.pPulseContext),ma_context_enumerate_devices_sink_callback__pulse,&callbackData);
if (pOP==NULL) {
Mf=MA_ERROR;
goto done;
}
Mf=ma_wait_for_operation__pulse(Mc,Mc->pulse.pMainLoop,pOP);
((ma_pa_operation_unref_proc)Mc->pulse.pa_operation_unref)(pOP);
if (Mf !=Ms) {
goto done;
}
}
if (!callbackData.isTerminated) {
pOP=((ma_pa_context_get_source_info_list_proc)Mc->pulse.pa_context_get_source_info_list)((ma_pa_context*)(Mc->pulse.pPulseContext),ma_context_enumerate_devices_source_callback__pulse,&callbackData);
if (pOP==NULL) {
Mf=MA_ERROR;
goto done;
}
Mf=ma_wait_for_operation__pulse(Mc,Mc->pulse.pMainLoop,pOP);
((ma_pa_operation_unref_proc)Mc->pulse.pa_operation_unref)(pOP);
if (Mf !=Ms) {
goto done;
}
}
done:
Mr Mf;
}
typedef struct
{
ma_device_info*pDeviceInfo;
M3 defaultDeviceIndex;
ma_bool32 foundDevice;
} ma_context_get_device_info_callback_data__pulse;
static Mv ma_context_get_device_info_sink_callback__pulse(ma_pa_context*pPulseContext,const ma_pa_sink_info*pInfo,int endOfList,Mv*pUserData)
{
ma_context_get_device_info_callback_data__pulse*pData=(ma_context_get_device_info_callback_data__pulse*)pUserData;
if (endOfList>0) {
Mr;
}
MA_ASSERT(pData !=NULL);
pData->foundDevice=MA_TRUE;
if (pInfo->name !=NULL) {
ma_strncpy_s(pData->pDeviceInfo->id.pulse,sizeof(pData->pDeviceInfo->id.pulse),pInfo->name,(size_t)-1);
}
if (pInfo->description !=NULL) {
ma_strncpy_s(pData->pDeviceInfo->name,sizeof(pData->pDeviceInfo->name),pInfo->description,(size_t)-1);
}
pData->pDeviceInfo->nativeDataFormats[0].format=ma_format_from_pulse(pInfo->sample_spec.format);
pData->pDeviceInfo->nativeDataFormats[0].Mh=pInfo->sample_spec.Mh;
pData->pDeviceInfo->nativeDataFormats[0].sampleRate=pInfo->sample_spec.rate;
pData->pDeviceInfo->nativeDataFormats[0].flags=0;
pData->pDeviceInfo->nativeDataFormatCount=1;
if (pData->defaultDeviceIndex==pInfo->index) {
pData->pDeviceInfo->isDefault=MA_TRUE;
}
(Mv)pPulseContext;
}
static Mv ma_context_get_device_info_source_callback__pulse(ma_pa_context*pPulseContext,const ma_pa_source_info*pInfo,int endOfList,Mv*pUserData)
{
ma_context_get_device_info_callback_data__pulse*pData=(ma_context_get_device_info_callback_data__pulse*)pUserData;
if (endOfList>0) {
Mr;
}
MA_ASSERT(pData !=NULL);
pData->foundDevice=MA_TRUE;
if (pInfo->name !=NULL) {
ma_strncpy_s(pData->pDeviceInfo->id.pulse,sizeof(pData->pDeviceInfo->id.pulse),pInfo->name,(size_t)-1);
}
if (pInfo->description !=NULL) {
ma_strncpy_s(pData->pDeviceInfo->name,sizeof(pData->pDeviceInfo->name),pInfo->description,(size_t)-1);
}
pData->pDeviceInfo->nativeDataFormats[0].format=ma_format_from_pulse(pInfo->sample_spec.format);
pData->pDeviceInfo->nativeDataFormats[0].Mh=pInfo->sample_spec.Mh;
pData->pDeviceInfo->nativeDataFormats[0].sampleRate=pInfo->sample_spec.rate;
pData->pDeviceInfo->nativeDataFormats[0].flags=0;
pData->pDeviceInfo->nativeDataFormatCount=1;
if (pData->defaultDeviceIndex==pInfo->index) {
pData->pDeviceInfo->isDefault=MA_TRUE;
}
(Mv)pPulseContext;
}
static Me ma_context_get_device_info__pulse(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
Me Mf=Ms;
ma_context_get_device_info_callback_data__pulse callbackData;
ma_pa_operation*pOP=NULL;
const char*pDeviceName=NULL;
MA_ASSERT(Mc !=NULL);
callbackData.pDeviceInfo=pDeviceInfo;
callbackData.foundDevice=MA_FALSE;
if (pDeviceID !=NULL) {
pDeviceName=pDeviceID->pulse;
} else {
pDeviceName=NULL;
}
Mf=ma_context_get_default_device_index__pulse(Mc,deviceType,&callbackData.defaultDeviceIndex);
if (deviceType==Mt) {
pOP=((ma_pa_context_get_sink_info_by_name_proc)Mc->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(Mc->pulse.pPulseContext),pDeviceName,ma_context_get_device_info_sink_callback__pulse,&callbackData);
} else {
pOP=((ma_pa_context_get_source_info_by_name_proc)Mc->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(Mc->pulse.pPulseContext),pDeviceName,ma_context_get_device_info_source_callback__pulse,&callbackData);
}
if (pOP !=NULL) {
ma_wait_for_operation_and_unref__pulse(Mc,Mc->pulse.pMainLoop,pOP);
} else {
Mf=MA_ERROR;
goto done;
}
if (!callbackData.foundDevice) {
Mf=MA_NO_DEVICE;
goto done;
}
done:
Mr Mf;
}
static Me ma_device_uninit__pulse(ma_device*Md)
{
ma_context*Mc;
MA_ASSERT(Md !=NULL);
Mc=Md->Mc;
MA_ASSERT(Mc !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)Mc->pulse.pa_stream_disconnect)((ma_pa_stream*)Md->pulse.pStreamCapture);
((ma_pa_stream_unref_proc)Mc->pulse.pa_stream_unref)((ma_pa_stream*)Md->pulse.pStreamCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)Mc->pulse.pa_stream_disconnect)((ma_pa_stream*)Md->pulse.pStreamPlayback);
((ma_pa_stream_unref_proc)Mc->pulse.pa_stream_unref)((ma_pa_stream*)Md->pulse.pStreamPlayback);
}
if (Md->type==ma_device_type_duplex) {
ma_duplex_rb_uninit(&Md->duplexRB);
}
((ma_pa_context_disconnect_proc)Mc->pulse.pa_context_disconnect)((ma_pa_context*)Md->pulse.pPulseContext);
((ma_pa_context_unref_proc)Mc->pulse.pa_context_unref)((ma_pa_context*)Md->pulse.pPulseContext);
((ma_pa_mainloop_free_proc)Mc->pulse.pa_mainloop_free)((ma_pa_mainloop*)Md->pulse.pMainLoop);
Mr Ms;
}
static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(M3 periodSizeInFrames,M3 periods,const ma_pa_sample_spec*ss)
{
ma_pa_buffer_attr attr;
attr.maxlength=periodSizeInFrames*periods*ma_get_bytes_per_frame(ma_format_from_pulse(ss->format),ss->Mh);
attr.tlength=attr.maxlength / periods;
attr.prebuf=(M3)-1;
attr.minreq=(M3)-1;
attr.fragsize=attr.maxlength / periods;
Mr attr;
}
static ma_pa_stream*ma_device__pa_stream_new__pulse(ma_device*Md,const char*pStreamName,const ma_pa_sample_spec*ss,const ma_pa_channel_map*cmap)
{
static ma_atomic_uint32 g_StreamCounter={ 0 };
char actualStreamName[256];
if (pStreamName !=NULL) {
ma_strncpy_s(actualStreamName,sizeof(actualStreamName),pStreamName,(size_t)-1);
} else {
const char* pBaseName = "miniaudio:";
size_t baseNameLen=strlen(pBaseName);
ma_strcpy_s(actualStreamName,sizeof(actualStreamName),pBaseName);
ma_itoa_s((int)ma_atomic_uint32_get(&g_StreamCounter),actualStreamName+baseNameLen,sizeof(actualStreamName)-baseNameLen,10);
}
ma_atomic_uint32_fetch_add(&g_StreamCounter,1);
Mr ((ma_pa_stream_new_proc)Md->Mc->pulse.pa_stream_new)((ma_pa_context*)Md->pulse.pPulseContext,actualStreamName,ss,cmap);
}
static Mv ma_device_on_read__pulse(ma_pa_stream*pStream,size_t byteCount,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
M3 bpf;
M3 deviceState;
M6 frameCount;
M6 framesProcessed;
MA_ASSERT(Md !=NULL);
deviceState=ma_device_get_state(Md);
if (deviceState !=ma_device_state_starting&&deviceState !=ma_device_state_started) {
Mr;
}
bpf=ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
MA_ASSERT(bpf>0);
frameCount=byteCount / bpf;
framesProcessed=0;
while (ma_device_get_state(Md)==ma_device_state_started&&framesProcessed<frameCount) {
const Mv*pMappedPCMFrames;
size_t bytesMapped;
M6 framesMapped;
int pulseResult=((ma_pa_stream_peek_proc)Md->Mc->pulse.pa_stream_peek)(pStream,&pMappedPCMFrames,&bytesMapped);
if (pulseResult<0) {
break;
}
framesMapped=bytesMapped / bpf;
if (framesMapped>0) {
if (pMappedPCMFrames !=NULL) {
ma_device_handle_backend_data_callback(Md,NULL,pMappedPCMFrames,framesMapped);
} else {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[PulseAudio] ma_device_on_read__pulse: Hole.\n");
}
pulseResult=((ma_pa_stream_drop_proc)Md->Mc->pulse.pa_stream_drop)(pStream);
if (pulseResult<0) {
break;
}
framesProcessed+=framesMapped;
} else {
break;
}
}
}
static Me ma_device_write_to_stream__pulse(ma_device*Md,ma_pa_stream*pStream,M6*pFramesProcessed)
{
Me Mf=Ms;
M6 framesProcessed=0;
size_t bytesMapped;
M3 bpf;
M3 deviceState;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pStream !=NULL);
bpf=ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
MA_ASSERT(bpf>0);
deviceState=ma_device_get_state(Md);
bytesMapped=((ma_pa_stream_writable_size_proc)Md->Mc->pulse.pa_stream_writable_size)(pStream);
if (bytesMapped !=(size_t)-1) {
if (bytesMapped>0) {
M6 framesMapped;
Mv*pMappedPCMFrames;
int pulseResult=((ma_pa_stream_begin_write_proc)Md->Mc->pulse.pa_stream_begin_write)(pStream,&pMappedPCMFrames,&bytesMapped);
if (pulseResult<0) {
Mf=ma_result_from_pulse(pulseResult);
goto done;
}
framesMapped=bytesMapped / bpf;
if (deviceState==ma_device_state_started||deviceState==ma_device_state_starting) {
ma_device_handle_backend_data_callback(Md,pMappedPCMFrames,NULL,framesMapped);
} else {
ma_silence_pcm_frames(pMappedPCMFrames,framesMapped,Md->playback.format,Md->playback.Mh);
}
pulseResult=((ma_pa_stream_write_proc)Md->Mc->pulse.pa_stream_write)(pStream,pMappedPCMFrames,bytesMapped,NULL,0,MA_PA_SEEK_RELATIVE);
if (pulseResult<0) {
Mf=ma_result_from_pulse(pulseResult);
goto done;
}
framesProcessed+=framesMapped;
} else {
Mf=Ms;
goto done;
}
} else {
Mf=MA_ERROR;
goto done;
}
done:
if (pFramesProcessed !=NULL) {
*pFramesProcessed=framesProcessed;
}
Mr Mf;
}
static Mv ma_device_on_write__pulse(ma_pa_stream*pStream,size_t byteCount,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
M3 bpf;
M6 frameCount;
M6 framesProcessed;
M3 deviceState;
Me Mf;
MA_ASSERT(Md !=NULL);
deviceState=ma_device_get_state(Md);
if (deviceState !=ma_device_state_starting&&deviceState !=ma_device_state_started) {
Mr;
}
bpf=ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
MA_ASSERT(bpf>0);
frameCount=byteCount / bpf;
framesProcessed=0;
while (framesProcessed<frameCount) {
M6 framesProcessedThisIteration;
deviceState=ma_device_get_state(Md);
if (deviceState !=ma_device_state_starting&&deviceState !=ma_device_state_started) {
break;
}
Mf=ma_device_write_to_stream__pulse(Md,pStream,&framesProcessedThisIteration);
if (Mf !=Ms) {
break;
}
framesProcessed+=framesProcessedThisIteration;
}
}
static Mv ma_device_on_suspended__pulse(ma_pa_stream*pStream,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
int suspended;
(Mv)pStream;
suspended=((ma_pa_stream_is_suspended_proc)Md->Mc->pulse.pa_stream_is_suspended)(pStream);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. pa_stream_is_suspended() returned %d.\n", suspended);
if (suspended<0) {
Mr;
}
if (suspended==1) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n");
ma_device__on_notification_stopped(Md);
} else {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n");
ma_device__on_notification_started(Md);
}
}
static Mv ma_device_on_rerouted__pulse(ma_pa_stream*pStream,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
(Mv)pStream;
(Mv)pUserData;
ma_device__on_notification_rerouted(Md);
}
static M3 ma_calculate_period_size_in_frames_from_descriptor__pulse(const ma_device_descriptor*pDescriptor,M3 nativeSampleRate,ma_performance_profile performanceProfile)
{
const M3 defaultPeriodSizeInMilliseconds_LowLatency=25;
const M3 defaultPeriodSizeInMilliseconds_Conservative=MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
MA_ASSERT(nativeSampleRate !=0);
if (pDescriptor->periodSizeInFrames==0) {
if (pDescriptor->periodSizeInMilliseconds==0) {
if (performanceProfile==ma_performance_profile_low_latency) {
Mr ma_calculate_buffer_size_in_frames_from_milliseconds(defaultPeriodSizeInMilliseconds_LowLatency,nativeSampleRate);
} else {
Mr ma_calculate_buffer_size_in_frames_from_milliseconds(defaultPeriodSizeInMilliseconds_Conservative,nativeSampleRate);
}
} else {
Mr ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds,nativeSampleRate);
}
} else {
Mr pDescriptor->periodSizeInFrames;
}
}
static Me ma_device_init__pulse(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf=Ms;
int error=0;
const char*devPlayback=NULL;
const char*devCapture=NULL;
ma_format format=ma_format_unknown;
M3 Mh=0;
M3 sampleRate=0;
ma_pa_sink_info sinkInfo;
ma_pa_source_info sourceInfo;
ma_pa_sample_spec ss;
ma_pa_channel_map cmap;
ma_pa_buffer_attr attr;
const ma_pa_sample_spec*pActualSS=NULL;
const ma_pa_buffer_attr*pActualAttr=NULL;
const ma_pa_channel_map*pActualChannelMap=NULL;
M3 iChannel;
ma_pa_stream_flags_t streamFlags;
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->pulse);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mo->playback.shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&Mo->capture.shareMode==ma_share_mode_exclusive)) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
if (Mp->pDeviceID !=NULL) {
devPlayback=Mp->pDeviceID->pulse;
}
format=Mp->format;
Mh=Mp->Mh;
sampleRate=Mp->sampleRate;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
if (pDescriptorCapture->pDeviceID !=NULL) {
devCapture=pDescriptorCapture->pDeviceID->pulse;
}
format=pDescriptorCapture->format;
Mh=pDescriptorCapture->Mh;
sampleRate=pDescriptorCapture->sampleRate;
}
Mf=ma_init_pa_mainloop_and_pa_context__pulse(Md->Mc,Md->Mc->pulse.pApplicationName,Md->Mc->pulse.pServerName,MA_FALSE,&Md->pulse.pMainLoop,&Md->pulse.pPulseContext);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize PA mainloop and context for device.\n");
Mr Mf;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
Mf=ma_context_get_source_info__pulse(Md->Mc,devCapture,&sourceInfo);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.");
goto on_error0;
}
ss=sourceInfo.sample_spec;
cmap=sourceInfo.channel_map;
if (pDescriptorCapture->Mh !=0) {
ss.Mh=pDescriptorCapture->Mh;
}
((ma_pa_channel_map_init_extend_proc)Md->Mc->pulse.pa_channel_map_init_extend)(&cmap,ss.Mh,Mo->pulse.channelMap);
if (pDescriptorCapture->sampleRate !=0) {
ss.rate=pDescriptorCapture->sampleRate;
}
streamFlags=MA_PA_STREAM_START_CORKED|MA_PA_STREAM_ADJUST_LATENCY;
if (ma_format_from_pulse(ss.format)==ma_format_unknown) {
if (ma_is_little_endian()) {
ss.format=MA_PA_SAMPLE_FLOAT32LE;
} else {
ss.format=MA_PA_SAMPLE_FLOAT32BE;
}
streamFlags|=MA_PA_STREAM_FIX_FORMAT;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n");
}
if (ss.rate==0) {
ss.rate=MA_DEFAULT_SAMPLE_RATE;
streamFlags|=MA_PA_STREAM_FIX_RATE;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate);
}
if (ss.Mh==0) {
ss.Mh=MA_DEFAULT_CHANNELS;
streamFlags|=MA_PA_STREAM_FIX_CHANNELS;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.Mh = 0. Defaulting to %d.\n", ss.Mh);
}
pDescriptorCapture->periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorCapture,ss.rate,Mo->performanceProfile);
attr=ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames,pDescriptorCapture->periodCount,&ss);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
Md->pulse.pStreamCapture=ma_device__pa_stream_new__pulse(Md,Mo->pulse.pStreamNameCapture,&ss,&cmap);
if (Md->pulse.pStreamCapture==NULL) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.\n");
Mf=MA_ERROR;
goto on_error0;
}
((ma_pa_stream_set_read_callback_proc)Md->Mc->pulse.pa_stream_set_read_callback)((ma_pa_stream*)Md->pulse.pStreamCapture,ma_device_on_read__pulse,Md);
((ma_pa_stream_set_suspended_callback_proc)Md->Mc->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)Md->pulse.pStreamCapture,ma_device_on_suspended__pulse,Md);
((ma_pa_stream_set_moved_callback_proc)Md->Mc->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)Md->pulse.pStreamCapture,ma_device_on_rerouted__pulse,Md);
if (devCapture !=NULL) {
streamFlags|=MA_PA_STREAM_DONT_MOVE;
}
error=((ma_pa_stream_connect_record_proc)Md->Mc->pulse.pa_stream_connect_record)((ma_pa_stream*)Md->pulse.pStreamCapture,devCapture,&attr,streamFlags);
if (error !=MA_PA_OK) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.");
Mf=ma_result_from_pulse(error);
goto on_error1;
}
Mf=ma_wait_for_pa_stream_to_connect__pulse(Md->Mc,Md->pulse.pMainLoop,(ma_pa_stream*)Md->pulse.pStreamCapture);
if (Mf !=Ms) {
goto on_error2;
}
pActualSS=((ma_pa_stream_get_sample_spec_proc)Md->Mc->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)Md->pulse.pStreamCapture);
if (pActualSS !=NULL) {
ss=*pActualSS;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture sample spec: format=%s, Mh=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.Mh, ss.rate);
} else {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve capture sample spec.\n");
}
pDescriptorCapture->format=ma_format_from_pulse(ss.format);
pDescriptorCapture->Mh=ss.Mh;
pDescriptorCapture->sampleRate=ss.rate;
if (pDescriptorCapture->format==ma_format_unknown||pDescriptorCapture->Mh==0||pDescriptorCapture->sampleRate==0) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Capture sample spec is invalid. Device unusable by miniaudio. format=%s, Mh=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorCapture->format), pDescriptorCapture->Mh, pDescriptorCapture->sampleRate);
Mf=MA_ERROR;
goto on_error4;
}
pActualChannelMap=((ma_pa_stream_get_channel_map_proc)Md->Mc->pulse.pa_stream_get_channel_map)((ma_pa_stream*)Md->pulse.pStreamCapture);
if (pActualChannelMap==NULL) {
pActualChannelMap=&cmap;
}
if (pDescriptorCapture->Mh>2) {
for (iChannel=0; iChannel<pDescriptorCapture->Mh; iChannel+=1) {
pDescriptorCapture->channelMap[iChannel]=ma_channel_position_from_pulse(pActualChannelMap->map[iChannel]);
}
} else {
if (pDescriptorCapture->Mh==1) {
pDescriptorCapture->channelMap[0]=MA_CHANNEL_MONO;
} else if (pDescriptorCapture->Mh==2) {
pDescriptorCapture->channelMap[0]=MA_CHANNEL_FRONT_LEFT;
pDescriptorCapture->channelMap[1]=MA_CHANNEL_FRONT_RIGHT;
} else {
MA_ASSERT(MA_FALSE);
}
}
pActualAttr=((ma_pa_stream_get_buffer_attr_proc)Md->Mc->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)Md->pulse.pStreamCapture);
if (pActualAttr !=NULL) {
attr=*pActualAttr;
}
if (attr.fragsize>0) {
pDescriptorCapture->periodCount=ma_max(attr.maxlength / attr.fragsize,1);
} else {
pDescriptorCapture->periodCount=1;
}
pDescriptorCapture->periodSizeInFrames=attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh) / pDescriptorCapture->periodCount;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Mf=ma_context_get_sink_info__pulse(Md->Mc,devPlayback,&sinkInfo);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.\n");
goto on_error2;
}
ss=sinkInfo.sample_spec;
cmap=sinkInfo.channel_map;
if (Mp->Mh !=0) {
ss.Mh=Mp->Mh;
}
((ma_pa_channel_map_init_extend_proc)Md->Mc->pulse.pa_channel_map_init_extend)(&cmap,ss.Mh,Mo->pulse.channelMap);
if (Mp->sampleRate !=0) {
ss.rate=Mp->sampleRate;
}
streamFlags=MA_PA_STREAM_START_CORKED|MA_PA_STREAM_ADJUST_LATENCY;
if (ma_format_from_pulse(ss.format)==ma_format_unknown) {
if (ma_is_little_endian()) {
ss.format=MA_PA_SAMPLE_FLOAT32LE;
} else {
ss.format=MA_PA_SAMPLE_FLOAT32BE;
}
streamFlags|=MA_PA_STREAM_FIX_FORMAT;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n");
}
if (ss.rate==0) {
ss.rate=MA_DEFAULT_SAMPLE_RATE;
streamFlags|=MA_PA_STREAM_FIX_RATE;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate);
}
if (ss.Mh==0) {
ss.Mh=MA_DEFAULT_CHANNELS;
streamFlags|=MA_PA_STREAM_FIX_CHANNELS;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.Mh = 0. Defaulting to %d.\n", ss.Mh);
}
Mp->periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__pulse(Mp,ss.rate,Mo->performanceProfile);
attr=ma_device__pa_buffer_attr_new(Mp->periodSizeInFrames,Mp->periodCount,&ss);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, Mp->periodSizeInFrames);
Md->pulse.pStreamPlayback=ma_device__pa_stream_new__pulse(Md,Mo->pulse.pStreamNamePlayback,&ss,&cmap);
if (Md->pulse.pStreamPlayback==NULL) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.\n");
Mf=MA_ERROR;
goto on_error2;
}
((ma_pa_stream_set_write_callback_proc)Md->Mc->pulse.pa_stream_set_write_callback)((ma_pa_stream*)Md->pulse.pStreamPlayback,ma_device_on_write__pulse,Md);
((ma_pa_stream_set_suspended_callback_proc)Md->Mc->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)Md->pulse.pStreamPlayback,ma_device_on_suspended__pulse,Md);
((ma_pa_stream_set_moved_callback_proc)Md->Mc->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)Md->pulse.pStreamPlayback,ma_device_on_rerouted__pulse,Md);
if (devPlayback !=NULL) {
streamFlags|=MA_PA_STREAM_DONT_MOVE;
}
error=((ma_pa_stream_connect_playback_proc)Md->Mc->pulse.pa_stream_connect_playback)((ma_pa_stream*)Md->pulse.pStreamPlayback,devPlayback,&attr,streamFlags,NULL,NULL);
if (error !=MA_PA_OK) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.");
Mf=ma_result_from_pulse(error);
goto on_error3;
}
Mf=ma_wait_for_pa_stream_to_connect__pulse(Md->Mc,Md->pulse.pMainLoop,(ma_pa_stream*)Md->pulse.pStreamPlayback);
if (Mf !=Ms) {
goto on_error3;
}
pActualSS=((ma_pa_stream_get_sample_spec_proc)Md->Mc->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)Md->pulse.pStreamPlayback);
if (pActualSS !=NULL) {
ss=*pActualSS;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback sample spec: format=%s, Mh=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.Mh, ss.rate);
} else {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve playback sample spec.\n");
}
Mp->format=ma_format_from_pulse(ss.format);
Mp->Mh=ss.Mh;
Mp->sampleRate=ss.rate;
if (Mp->format==ma_format_unknown||Mp->Mh==0||Mp->sampleRate==0) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Playback sample spec is invalid. Device unusable by miniaudio. format=%s, Mh=%d, sampleRate=%d.\n", ma_get_format_name(Mp->format), Mp->Mh, Mp->sampleRate);
Mf=MA_ERROR;
goto on_error4;
}
pActualChannelMap=((ma_pa_stream_get_channel_map_proc)Md->Mc->pulse.pa_stream_get_channel_map)((ma_pa_stream*)Md->pulse.pStreamPlayback);
if (pActualChannelMap==NULL) {
pActualChannelMap=&cmap;
}
if (Mp->Mh>2) {
for (iChannel=0; iChannel<Mp->Mh; iChannel+=1) {
Mp->channelMap[iChannel]=ma_channel_position_from_pulse(pActualChannelMap->map[iChannel]);
}
} else {
if (Mp->Mh==1) {
Mp->channelMap[0]=MA_CHANNEL_MONO;
} else if (Mp->Mh==2) {
Mp->channelMap[0]=MA_CHANNEL_FRONT_LEFT;
Mp->channelMap[1]=MA_CHANNEL_FRONT_RIGHT;
} else {
MA_ASSERT(MA_FALSE);
}
}
pActualAttr=((ma_pa_stream_get_buffer_attr_proc)Md->Mc->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)Md->pulse.pStreamPlayback);
if (pActualAttr !=NULL) {
attr=*pActualAttr;
}
if (attr.tlength>0) {
Mp->periodCount=ma_max(attr.maxlength / attr.tlength,1);
} else {
Mp->periodCount=1;
}
Mp->periodSizeInFrames=attr.maxlength / ma_get_bytes_per_frame(Mp->format,Mp->Mh) / Mp->periodCount;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, Mp->periodSizeInFrames);
}
if (Mo->deviceType==ma_device_type_duplex) {
ma_format rbFormat=(format !=ma_format_unknown)?format:pDescriptorCapture->format;
M3 rbChannels=(Mh>0)?Mh:pDescriptorCapture->Mh;
M3 rbSampleRate=(sampleRate>0)?sampleRate:pDescriptorCapture->sampleRate;
Mf=ma_duplex_rb_init(rbFormat,rbChannels,rbSampleRate,pDescriptorCapture->sampleRate,pDescriptorCapture->periodSizeInFrames,&Md->Mc->allocationCallbacks,&Md->duplexRB);
if (Mf !=Ms) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer. %s.\n", ma_result_description(Mf));
goto on_error4;
}
}
Mr Ms;
on_error4:
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)Md->Mc->pulse.pa_stream_disconnect)((ma_pa_stream*)Md->pulse.pStreamPlayback);
}
on_error3:
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
((ma_pa_stream_unref_proc)Md->Mc->pulse.pa_stream_unref)((ma_pa_stream*)Md->pulse.pStreamPlayback);
}
on_error2:
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)Md->Mc->pulse.pa_stream_disconnect)((ma_pa_stream*)Md->pulse.pStreamCapture);
}
on_error1:
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
((ma_pa_stream_unref_proc)Md->Mc->pulse.pa_stream_unref)((ma_pa_stream*)Md->pulse.pStreamCapture);
}
on_error0:
Mr Mf;
}
static Mv ma_pulse_operation_complete_callback(ma_pa_stream*pStream,int success,Mv*pUserData)
{
ma_bool32*pIsSuccessful=(ma_bool32*)pUserData;
MA_ASSERT(pIsSuccessful !=NULL);
*pIsSuccessful=(ma_bool32)success;
(Mv)pStream;
}
static Me ma_device__cork_stream__pulse(ma_device*Md,ma_device_type deviceType,int cork)
{
ma_context*Mc=Md->Mc;
ma_bool32 wasSuccessful;
ma_pa_stream*pStream;
ma_pa_operation*pOP;
Me Mf;
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
wasSuccessful=MA_FALSE;
pStream=(ma_pa_stream*)((deviceType==ma_device_type_capture)?Md->pulse.pStreamCapture:Md->pulse.pStreamPlayback);
MA_ASSERT(pStream !=NULL);
pOP=((ma_pa_stream_cork_proc)Mc->pulse.pa_stream_cork)(pStream,cork,ma_pulse_operation_complete_callback,&wasSuccessful);
if (pOP==NULL) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.");
Mr MA_ERROR;
}
Mf=ma_wait_for_operation_and_unref__pulse(Md->Mc,Md->pulse.pMainLoop,pOP);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.");
Mr Mf;
}
if (!wasSuccessful) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to %s PulseAudio stream.", (cork) ? "stop" : "start");
Mr MA_ERROR;
}
Mr Ms;
}
static Me ma_device_start__pulse(ma_device*Md)
{
Me Mf;
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
Mf=ma_device__cork_stream__pulse(Md,ma_device_type_capture,0);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_device_write_to_stream__pulse(Md,(ma_pa_stream*)(Md->pulse.pStreamPlayback),NULL);
Mf=ma_device__cork_stream__pulse(Md,Mt,0);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_stop__pulse(ma_device*Md)
{
Me Mf;
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
Mf=ma_device__cork_stream__pulse(Md,ma_device_type_capture,1);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
#if 0
ma_pa_operation*pOP=((ma_pa_stream_drain_proc)Md->Mc->pulse.pa_stream_drain)((ma_pa_stream*)Md->pulse.pStreamPlayback,ma_pulse_operation_complete_callback,&wasSuccessful);
ma_wait_for_operation_and_unref__pulse(Md->Mc,Md->pulse.pMainLoop,pOP);
#endif
Mf=ma_device__cork_stream__pulse(Md,Mt,1);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_data_loop__pulse(ma_device*Md)
{
int resultPA;
MA_ASSERT(Md !=NULL);
while (ma_device_get_state(Md)==ma_device_state_started) {
resultPA=((ma_pa_mainloop_iterate_proc)Md->Mc->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)Md->pulse.pMainLoop,1,NULL);
if (resultPA<0) {
break;
}
}
Mr Ms;
}
static Me ma_device_data_loop_wakeup__pulse(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
((ma_pa_mainloop_wakeup_proc)Md->Mc->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)Md->pulse.pMainLoop);
Mr Ms;
}
static Me ma_context_uninit__pulse(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_pulseaudio);
((ma_pa_context_disconnect_proc)Mc->pulse.pa_context_disconnect)((ma_pa_context*)Mc->pulse.pPulseContext);
((ma_pa_context_unref_proc)Mc->pulse.pa_context_unref)((ma_pa_context*)Mc->pulse.pPulseContext);
((ma_pa_mainloop_free_proc)Mc->pulse.pa_mainloop_free)((ma_pa_mainloop*)Mc->pulse.pMainLoop);
ma_free(Mc->pulse.pServerName,&Mc->allocationCallbacks);
ma_free(Mc->pulse.pApplicationName,&Mc->allocationCallbacks);
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(ma_context_get_log(Mc),Mc->pulse.pulseSO);
#endif
Mr Ms;
}
static Me ma_context_init__pulse(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
Me Mf;
#ifndef MA_NO_RUNTIME_LINKING
const char*libpulseNames[]={
"libpulse.so","libpulse.so.0"
};
size_t i;
for (i=0; i<ma_countof(libpulseNames);++i) {
Mc->pulse.pulseSO=ma_dlopen(ma_context_get_log(Mc),libpulseNames[i]);
if (Mc->pulse.pulseSO !=NULL) {
break;
}
}
if (Mc->pulse.pulseSO==NULL) {
Mr MA_NO_BACKEND;
}
Mc->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_mainloop_new");
Mc->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_mainloop_free");
Mc->pulse.pa_mainloop_quit = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_mainloop_quit");
Mc->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_mainloop_get_api");
Mc->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_mainloop_iterate");
Mc->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_mainloop_wakeup");
Mc->pulse.pa_threaded_mainloop_new = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_new");
Mc->pulse.pa_threaded_mainloop_free = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_free");
Mc->pulse.pa_threaded_mainloop_start = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_start");
Mc->pulse.pa_threaded_mainloop_stop = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_stop");
Mc->pulse.pa_threaded_mainloop_lock = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_lock");
Mc->pulse.pa_threaded_mainloop_unlock = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_unlock");
Mc->pulse.pa_threaded_mainloop_wait = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_wait");
Mc->pulse.pa_threaded_mainloop_signal = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_signal");
Mc->pulse.pa_threaded_mainloop_accept = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_accept");
Mc->pulse.pa_threaded_mainloop_get_retval = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_get_retval");
Mc->pulse.pa_threaded_mainloop_get_api = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_get_api");
Mc->pulse.pa_threaded_mainloop_in_thread = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_in_thread");
Mc->pulse.pa_threaded_mainloop_set_name = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_threaded_mainloop_set_name");
Mc->pulse.pa_context_new = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_new");
Mc->pulse.pa_context_unref = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_unref");
Mc->pulse.pa_context_connect = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_connect");
Mc->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_disconnect");
Mc->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_set_state_callback");
Mc->pulse.pa_context_get_state = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_get_state");
Mc->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_get_sink_info_list");
Mc->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_get_source_info_list");
Mc->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_get_sink_info_by_name");
Mc->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_context_get_source_info_by_name");
Mc->pulse.pa_operation_unref = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_operation_unref");
Mc->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_operation_get_state");
Mc->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_channel_map_init_extend");
Mc->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_channel_map_valid");
Mc->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_channel_map_compatible");
Mc->pulse.pa_stream_new = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_new");
Mc->pulse.pa_stream_unref = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_unref");
Mc->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_connect_playback");
Mc->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_connect_record");
Mc->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_disconnect");
Mc->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_get_state");
Mc->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_get_sample_spec");
Mc->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_get_channel_map");
Mc->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_get_buffer_attr");
Mc->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_set_buffer_attr");
Mc->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_get_device_name");
Mc->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_set_write_callback");
Mc->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_set_read_callback");
Mc->pulse.pa_stream_set_suspended_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_set_suspended_callback");
Mc->pulse.pa_stream_set_moved_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_set_moved_callback");
Mc->pulse.pa_stream_is_suspended = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_is_suspended");
Mc->pulse.pa_stream_flush = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_flush");
Mc->pulse.pa_stream_drain = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_drain");
Mc->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_is_corked");
Mc->pulse.pa_stream_cork = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_cork");
Mc->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_trigger");
Mc->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_begin_write");
Mc->pulse.pa_stream_write = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_write");
Mc->pulse.pa_stream_peek = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_peek");
Mc->pulse.pa_stream_drop = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_drop");
Mc->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_writable_size");
Mc->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->pulse.pulseSO, "pa_stream_readable_size");
#else
ma_pa_mainloop_new_proc _pa_mainloop_new=pa_mainloop_new;
ma_pa_mainloop_free_proc _pa_mainloop_free=pa_mainloop_free;
ma_pa_mainloop_quit_proc _pa_mainloop_quit=pa_mainloop_quit;
ma_pa_mainloop_get_api_proc _pa_mainloop_get_api=pa_mainloop_get_api;
ma_pa_mainloop_iterate_proc _pa_mainloop_iterate=pa_mainloop_iterate;
ma_pa_mainloop_wakeup_proc _pa_mainloop_wakeup=pa_mainloop_wakeup;
ma_pa_threaded_mainloop_new_proc _pa_threaded_mainloop_new=pa_threaded_mainloop_new;
ma_pa_threaded_mainloop_free_proc _pa_threaded_mainloop_free=pa_threaded_mainloop_free;
ma_pa_threaded_mainloop_start_proc _pa_threaded_mainloop_start=pa_threaded_mainloop_start;
ma_pa_threaded_mainloop_stop_proc _pa_threaded_mainloop_stop=pa_threaded_mainloop_stop;
ma_pa_threaded_mainloop_lock_proc _pa_threaded_mainloop_lock=pa_threaded_mainloop_lock;
ma_pa_threaded_mainloop_unlock_proc _pa_threaded_mainloop_unlock=pa_threaded_mainloop_unlock;
ma_pa_threaded_mainloop_wait_proc _pa_threaded_mainloop_wait=pa_threaded_mainloop_wait;
ma_pa_threaded_mainloop_signal_proc _pa_threaded_mainloop_signal=pa_threaded_mainloop_signal;
ma_pa_threaded_mainloop_accept_proc _pa_threaded_mainloop_accept=pa_threaded_mainloop_accept;
ma_pa_threaded_mainloop_get_retval_proc _pa_threaded_mainloop_get_retval=pa_threaded_mainloop_get_retval;
ma_pa_threaded_mainloop_get_api_proc _pa_threaded_mainloop_get_api=pa_threaded_mainloop_get_api;
ma_pa_threaded_mainloop_in_thread_proc _pa_threaded_mainloop_in_thread=pa_threaded_mainloop_in_thread;
ma_pa_threaded_mainloop_set_name_proc _pa_threaded_mainloop_set_name=pa_threaded_mainloop_set_name;
ma_pa_context_new_proc _pa_context_new=pa_context_new;
ma_pa_context_unref_proc _pa_context_unref=pa_context_unref;
ma_pa_context_connect_proc _pa_context_connect=pa_context_connect;
ma_pa_context_disconnect_proc _pa_context_disconnect=pa_context_disconnect;
ma_pa_context_set_state_callback_proc _pa_context_set_state_callback=pa_context_set_state_callback;
ma_pa_context_get_state_proc _pa_context_get_state=pa_context_get_state;
ma_pa_context_get_sink_info_list_proc _pa_context_get_sink_info_list=pa_context_get_sink_info_list;
ma_pa_context_get_source_info_list_proc _pa_context_get_source_info_list=pa_context_get_source_info_list;
ma_pa_context_get_sink_info_by_name_proc _pa_context_get_sink_info_by_name=pa_context_get_sink_info_by_name;
ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name=pa_context_get_source_info_by_name;
ma_pa_operation_unref_proc _pa_operation_unref=pa_operation_unref;
ma_pa_operation_get_state_proc _pa_operation_get_state=pa_operation_get_state;
ma_pa_channel_map_init_extend_proc _pa_channel_map_init_extend=pa_channel_map_init_extend;
ma_pa_channel_map_valid_proc _pa_channel_map_valid=pa_channel_map_valid;
ma_pa_channel_map_compatible_proc _pa_channel_map_compatible=pa_channel_map_compatible;
ma_pa_stream_new_proc _pa_stream_new=pa_stream_new;
ma_pa_stream_unref_proc _pa_stream_unref=pa_stream_unref;
ma_pa_stream_connect_playback_proc _pa_stream_connect_playback=pa_stream_connect_playback;
ma_pa_stream_connect_record_proc _pa_stream_connect_record=pa_stream_connect_record;
ma_pa_stream_disconnect_proc _pa_stream_disconnect=pa_stream_disconnect;
ma_pa_stream_get_state_proc _pa_stream_get_state=pa_stream_get_state;
ma_pa_stream_get_sample_spec_proc _pa_stream_get_sample_spec=pa_stream_get_sample_spec;
ma_pa_stream_get_channel_map_proc _pa_stream_get_channel_map=pa_stream_get_channel_map;
ma_pa_stream_get_buffer_attr_proc _pa_stream_get_buffer_attr=pa_stream_get_buffer_attr;
ma_pa_stream_set_buffer_attr_proc _pa_stream_set_buffer_attr=pa_stream_set_buffer_attr;
ma_pa_stream_get_device_name_proc _pa_stream_get_device_name=pa_stream_get_device_name;
ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback=pa_stream_set_write_callback;
ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback=pa_stream_set_read_callback;
ma_pa_stream_set_suspended_callback_proc _pa_stream_set_suspended_callback=pa_stream_set_suspended_callback;
ma_pa_stream_set_moved_callback_proc _pa_stream_set_moved_callback=pa_stream_set_moved_callback;
ma_pa_stream_is_suspended_proc _pa_stream_is_suspended=pa_stream_is_suspended;
ma_pa_stream_flush_proc _pa_stream_flush=pa_stream_flush;
ma_pa_stream_drain_proc _pa_stream_drain=pa_stream_drain;
ma_pa_stream_is_corked_proc _pa_stream_is_corked=pa_stream_is_corked;
ma_pa_stream_cork_proc _pa_stream_cork=pa_stream_cork;
ma_pa_stream_trigger_proc _pa_stream_trigger=pa_stream_trigger;
ma_pa_stream_begin_write_proc _pa_stream_begin_write=pa_stream_begin_write;
ma_pa_stream_write_proc _pa_stream_write=pa_stream_write;
ma_pa_stream_peek_proc _pa_stream_peek=pa_stream_peek;
ma_pa_stream_drop_proc _pa_stream_drop=pa_stream_drop;
ma_pa_stream_writable_size_proc _pa_stream_writable_size=pa_stream_writable_size;
ma_pa_stream_readable_size_proc _pa_stream_readable_size=pa_stream_readable_size;
Mc->pulse.pa_mainloop_new=(ma_proc)_pa_mainloop_new;
Mc->pulse.pa_mainloop_free=(ma_proc)_pa_mainloop_free;
Mc->pulse.pa_mainloop_quit=(ma_proc)_pa_mainloop_quit;
Mc->pulse.pa_mainloop_get_api=(ma_proc)_pa_mainloop_get_api;
Mc->pulse.pa_mainloop_iterate=(ma_proc)_pa_mainloop_iterate;
Mc->pulse.pa_mainloop_wakeup=(ma_proc)_pa_mainloop_wakeup;
Mc->pulse.pa_threaded_mainloop_new=(ma_proc)_pa_threaded_mainloop_new;
Mc->pulse.pa_threaded_mainloop_free=(ma_proc)_pa_threaded_mainloop_free;
Mc->pulse.pa_threaded_mainloop_start=(ma_proc)_pa_threaded_mainloop_start;
Mc->pulse.pa_threaded_mainloop_stop=(ma_proc)_pa_threaded_mainloop_stop;
Mc->pulse.pa_threaded_mainloop_lock=(ma_proc)_pa_threaded_mainloop_lock;
Mc->pulse.pa_threaded_mainloop_unlock=(ma_proc)_pa_threaded_mainloop_unlock;
Mc->pulse.pa_threaded_mainloop_wait=(ma_proc)_pa_threaded_mainloop_wait;
Mc->pulse.pa_threaded_mainloop_signal=(ma_proc)_pa_threaded_mainloop_signal;
Mc->pulse.pa_threaded_mainloop_accept=(ma_proc)_pa_threaded_mainloop_accept;
Mc->pulse.pa_threaded_mainloop_get_retval=(ma_proc)_pa_threaded_mainloop_get_retval;
Mc->pulse.pa_threaded_mainloop_get_api=(ma_proc)_pa_threaded_mainloop_get_api;
Mc->pulse.pa_threaded_mainloop_in_thread=(ma_proc)_pa_threaded_mainloop_in_thread;
Mc->pulse.pa_threaded_mainloop_set_name=(ma_proc)_pa_threaded_mainloop_set_name;
Mc->pulse.pa_context_new=(ma_proc)_pa_context_new;
Mc->pulse.pa_context_unref=(ma_proc)_pa_context_unref;
Mc->pulse.pa_context_connect=(ma_proc)_pa_context_connect;
Mc->pulse.pa_context_disconnect=(ma_proc)_pa_context_disconnect;
Mc->pulse.pa_context_set_state_callback=(ma_proc)_pa_context_set_state_callback;
Mc->pulse.pa_context_get_state=(ma_proc)_pa_context_get_state;
Mc->pulse.pa_context_get_sink_info_list=(ma_proc)_pa_context_get_sink_info_list;
Mc->pulse.pa_context_get_source_info_list=(ma_proc)_pa_context_get_source_info_list;
Mc->pulse.pa_context_get_sink_info_by_name=(ma_proc)_pa_context_get_sink_info_by_name;
Mc->pulse.pa_context_get_source_info_by_name=(ma_proc)_pa_context_get_source_info_by_name;
Mc->pulse.pa_operation_unref=(ma_proc)_pa_operation_unref;
Mc->pulse.pa_operation_get_state=(ma_proc)_pa_operation_get_state;
Mc->pulse.pa_channel_map_init_extend=(ma_proc)_pa_channel_map_init_extend;
Mc->pulse.pa_channel_map_valid=(ma_proc)_pa_channel_map_valid;
Mc->pulse.pa_channel_map_compatible=(ma_proc)_pa_channel_map_compatible;
Mc->pulse.pa_stream_new=(ma_proc)_pa_stream_new;
Mc->pulse.pa_stream_unref=(ma_proc)_pa_stream_unref;
Mc->pulse.pa_stream_connect_playback=(ma_proc)_pa_stream_connect_playback;
Mc->pulse.pa_stream_connect_record=(ma_proc)_pa_stream_connect_record;
Mc->pulse.pa_stream_disconnect=(ma_proc)_pa_stream_disconnect;
Mc->pulse.pa_stream_get_state=(ma_proc)_pa_stream_get_state;
Mc->pulse.pa_stream_get_sample_spec=(ma_proc)_pa_stream_get_sample_spec;
Mc->pulse.pa_stream_get_channel_map=(ma_proc)_pa_stream_get_channel_map;
Mc->pulse.pa_stream_get_buffer_attr=(ma_proc)_pa_stream_get_buffer_attr;
Mc->pulse.pa_stream_set_buffer_attr=(ma_proc)_pa_stream_set_buffer_attr;
Mc->pulse.pa_stream_get_device_name=(ma_proc)_pa_stream_get_device_name;
Mc->pulse.pa_stream_set_write_callback=(ma_proc)_pa_stream_set_write_callback;
Mc->pulse.pa_stream_set_read_callback=(ma_proc)_pa_stream_set_read_callback;
Mc->pulse.pa_stream_set_suspended_callback=(ma_proc)_pa_stream_set_suspended_callback;
Mc->pulse.pa_stream_set_moved_callback=(ma_proc)_pa_stream_set_moved_callback;
Mc->pulse.pa_stream_is_suspended=(ma_proc)_pa_stream_is_suspended;
Mc->pulse.pa_stream_flush=(ma_proc)_pa_stream_flush;
Mc->pulse.pa_stream_drain=(ma_proc)_pa_stream_drain;
Mc->pulse.pa_stream_is_corked=(ma_proc)_pa_stream_is_corked;
Mc->pulse.pa_stream_cork=(ma_proc)_pa_stream_cork;
Mc->pulse.pa_stream_trigger=(ma_proc)_pa_stream_trigger;
Mc->pulse.pa_stream_begin_write=(ma_proc)_pa_stream_begin_write;
Mc->pulse.pa_stream_write=(ma_proc)_pa_stream_write;
Mc->pulse.pa_stream_peek=(ma_proc)_pa_stream_peek;
Mc->pulse.pa_stream_drop=(ma_proc)_pa_stream_drop;
Mc->pulse.pa_stream_writable_size=(ma_proc)_pa_stream_writable_size;
Mc->pulse.pa_stream_readable_size=(ma_proc)_pa_stream_readable_size;
#endif
Mc->pulse.pApplicationName=ma_copy_string(Mo->pulse.pApplicationName,&Mc->allocationCallbacks);
if (Mc->pulse.pApplicationName==NULL&&Mo->pulse.pApplicationName !=NULL) {
Mr MA_OUT_OF_MEMORY;
}
Mc->pulse.pServerName=ma_copy_string(Mo->pulse.pServerName,&Mc->allocationCallbacks);
if (Mc->pulse.pServerName==NULL&&Mo->pulse.pServerName !=NULL) {
ma_free(Mc->pulse.pApplicationName,&Mc->allocationCallbacks);
Mr MA_OUT_OF_MEMORY;
}
Mf=ma_init_pa_mainloop_and_pa_context__pulse(Mc,Mo->pulse.pApplicationName,Mo->pulse.pServerName,Mo->pulse.tryAutoSpawn,&Mc->pulse.pMainLoop,&Mc->pulse.pPulseContext);
if (Mf !=Ms) {
ma_free(Mc->pulse.pServerName,&Mc->allocationCallbacks);
ma_free(Mc->pulse.pApplicationName,&Mc->allocationCallbacks);
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(ma_context_get_log(Mc),Mc->pulse.pulseSO);
#endif
Mr Mf;
}
pCallbacks->onContextInit=ma_context_init__pulse;
pCallbacks->onContextUninit=ma_context_uninit__pulse;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__pulse;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__pulse;
pCallbacks->onDeviceInit=ma_device_init__pulse;
pCallbacks->onDeviceUninit=ma_device_uninit__pulse;
pCallbacks->onDeviceStart=ma_device_start__pulse;
pCallbacks->onDeviceStop=ma_device_stop__pulse;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=ma_device_data_loop__pulse;
pCallbacks->onDeviceDataLoopWakeup=ma_device_data_loop_wakeup__pulse;
Mr Ms;
}
#endif
#ifdef MA_HAS_JACK
#ifdef MA_NO_RUNTIME_LINKING
#include <jack/jack.h>
typedef jack_nframes_t ma_jack_nframes_t;
typedef jack_options_t ma_jack_options_t;
typedef jack_status_t ma_jack_status_t;
typedef jack_client_t ma_jack_client_t;
typedef jack_port_t ma_jack_port_t;
typedef JackProcessCallback ma_JackProcessCallback;
typedef JackBufferSizeCallback ma_JackBufferSizeCallback;
typedef JackShutdownCallback ma_JackShutdownCallback;
#define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE
#define ma_JackNoStartServer JackNoStartServer
#define ma_JackPortIsInput JackPortIsInput
#define ma_JackPortIsOutput JackPortIsOutput
#define ma_JackPortIsPhysical JackPortIsPhysical
#else
typedef M3 ma_jack_nframes_t;
typedef int ma_jack_options_t;
typedef int ma_jack_status_t;
typedef struct ma_jack_client_t ma_jack_client_t;
typedef struct ma_jack_port_t ma_jack_port_t;
typedef int (*ma_JackProcessCallback) (ma_jack_nframes_t nframes,Mv*arg);
typedef int (*ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes,Mv*arg);
typedef Mv (*ma_JackShutdownCallback) (Mv*arg);
#define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio"
#define ma_JackNoStartServer 1
#define ma_JackPortIsInput 1
#define ma_JackPortIsOutput 2
#define ma_JackPortIsPhysical 4
#endif
typedef ma_jack_client_t*(*ma_jack_client_open_proc) (const char*client_name,ma_jack_options_t options,ma_jack_status_t*status,...);
typedef int (*ma_jack_client_close_proc) (ma_jack_client_t*client);
typedef int (*ma_jack_client_name_size_proc) (Mv);
typedef int (*ma_jack_set_process_callback_proc) (ma_jack_client_t*client,ma_JackProcessCallback process_callback,Mv*arg);
typedef int (*ma_jack_set_buffer_size_callback_proc)(ma_jack_client_t*client,ma_JackBufferSizeCallback bufsize_callback,Mv*arg);
typedef Mv (*ma_jack_on_shutdown_proc) (ma_jack_client_t*client,ma_JackShutdownCallback function,Mv*arg);
typedef ma_jack_nframes_t (*ma_jack_get_sample_rate_proc) (ma_jack_client_t*client);
typedef ma_jack_nframes_t (*ma_jack_get_buffer_size_proc) (ma_jack_client_t*client);
typedef const char**(*ma_jack_get_ports_proc) (ma_jack_client_t*client,const char*port_name_pattern,const char*type_name_pattern,unsigned long flags);
typedef int (*ma_jack_activate_proc) (ma_jack_client_t*client);
typedef int (*ma_jack_deactivate_proc) (ma_jack_client_t*client);
typedef int (*ma_jack_connect_proc) (ma_jack_client_t*client,const char*source_port,const char*destination_port);
typedef ma_jack_port_t*(*ma_jack_port_register_proc) (ma_jack_client_t*client,const char*port_name,const char*port_type,unsigned long flags,unsigned long buffer_size);
typedef const char*(*ma_jack_port_name_proc) (const ma_jack_port_t*port);
typedef Mv*(*ma_jack_port_get_buffer_proc) (ma_jack_port_t*port,ma_jack_nframes_t nframes);
typedef Mv (*ma_jack_free_proc) (Mv*ptr);
static Me ma_context_open_client__jack(ma_context*Mc,ma_jack_client_t**ppClient)
{
size_t maxClientNameSize;
char clientName[256];
ma_jack_status_t status;
ma_jack_client_t*pClient;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppClient !=NULL);
if (ppClient) {
*ppClient=NULL;
}
maxClientNameSize=((ma_jack_client_name_size_proc)Mc->jack.jack_client_name_size)();
ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (Mc->jack.pClientName != NULL) ? Mc->jack.pClientName : "miniaudio", (size_t)-1);
pClient=((ma_jack_client_open_proc)Mc->jack.jack_client_open)(clientName,(Mc->jack.tryStartServer)?0:ma_JackNoStartServer,&status,NULL);
if (pClient==NULL) {
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
if (ppClient) {
*ppClient=pClient;
}
Mr Ms;
}
static Me ma_context_enumerate_devices__jack(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_bool32 cbResult=MA_TRUE;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
deviceInfo.isDefault=MA_TRUE;
cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
}
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
deviceInfo.isDefault=MA_TRUE;
cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
(Mv)cbResult;
Mr Ms;
}
static Me ma_context_get_device_info__jack(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
ma_jack_client_t*pClient;
Me Mf;
const char**ppPorts;
MA_ASSERT(Mc !=NULL);
if (pDeviceID !=NULL&&pDeviceID->jack !=0) {
Mr MA_NO_DEVICE;
}
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
pDeviceInfo->isDefault=MA_TRUE;
pDeviceInfo->nativeDataFormats[0].format=ma_format_f32;
Mf=ma_context_open_client__jack(Mc,&pClient);
if (Mf !=Ms) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.");
Mr Mf;
}
pDeviceInfo->nativeDataFormats[0].sampleRate=((ma_jack_get_sample_rate_proc)Mc->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient);
pDeviceInfo->nativeDataFormats[0].Mh=0;
ppPorts=((ma_jack_get_ports_proc)Mc->jack.jack_get_ports)((ma_jack_client_t*)pClient,NULL,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsPhysical|((deviceType==Mt)?ma_JackPortIsInput:ma_JackPortIsOutput));
if (ppPorts==NULL) {
((ma_jack_client_close_proc)Mc->jack.jack_client_close)((ma_jack_client_t*)pClient);
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
while (ppPorts[pDeviceInfo->nativeDataFormats[0].Mh] !=NULL) {
pDeviceInfo->nativeDataFormats[0].Mh+=1;
}
pDeviceInfo->nativeDataFormats[0].flags=0;
pDeviceInfo->nativeDataFormatCount=1;
((ma_jack_free_proc)Mc->jack.jack_free)((Mv*)ppPorts);
((ma_jack_client_close_proc)Mc->jack.jack_client_close)((ma_jack_client_t*)pClient);
(Mv)Mc;
Mr Ms;
}
static Me ma_device_uninit__jack(ma_device*Md)
{
ma_context*Mc;
MA_ASSERT(Md !=NULL);
Mc=Md->Mc;
MA_ASSERT(Mc !=NULL);
if (Md->jack.pClient !=NULL) {
((ma_jack_client_close_proc)Mc->jack.jack_client_close)((ma_jack_client_t*)Md->jack.pClient);
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
ma_free(Md->jack.pIntermediaryBufferCapture,&Md->Mc->allocationCallbacks);
ma_free(Md->jack.ppPortsCapture,&Md->Mc->allocationCallbacks);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_free(Md->jack.pIntermediaryBufferPlayback,&Md->Mc->allocationCallbacks);
ma_free(Md->jack.ppPortsPlayback,&Md->Mc->allocationCallbacks);
}
Mr Ms;
}
static Mv ma_device__jack_shutdown_callback(Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
ma_device_stop(Md);
}
static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
size_t newBufferSize=frameCount*(Md->capture.internalChannels*ma_get_bytes_per_sample(Md->capture.internalFormat));
float*pNewBuffer=(float*)ma_calloc(newBufferSize,&Md->Mc->allocationCallbacks);
if (pNewBuffer==NULL) {
Mr MA_OUT_OF_MEMORY;
}
ma_free(Md->jack.pIntermediaryBufferCapture,&Md->Mc->allocationCallbacks);
Md->jack.pIntermediaryBufferCapture=pNewBuffer;
Md->playback.internalPeriodSizeInFrames=frameCount;
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
size_t newBufferSize=frameCount*(Md->playback.internalChannels*ma_get_bytes_per_sample(Md->playback.internalFormat));
float*pNewBuffer=(float*)ma_calloc(newBufferSize,&Md->Mc->allocationCallbacks);
if (pNewBuffer==NULL) {
Mr MA_OUT_OF_MEMORY;
}
ma_free(Md->jack.pIntermediaryBufferPlayback,&Md->Mc->allocationCallbacks);
Md->jack.pIntermediaryBufferPlayback=pNewBuffer;
Md->playback.internalPeriodSizeInFrames=frameCount;
}
Mr 0;
}
static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount,Mv*pUserData)
{
ma_device*Md;
ma_context*Mc;
M3 iChannel;
Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
Mc=Md->Mc;
MA_ASSERT(Mc !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
for (iChannel=0; iChannel<Md->capture.internalChannels;++iChannel) {
const float*pSrc=(const float*)((ma_jack_port_get_buffer_proc)Mc->jack.jack_port_get_buffer)((ma_jack_port_t*)Md->jack.ppPortsCapture[iChannel],frameCount);
if (pSrc !=NULL) {
float*pDst=Md->jack.pIntermediaryBufferCapture+iChannel;
ma_jack_nframes_t iFrame;
for (iFrame=0; iFrame<frameCount;++iFrame) {
*pDst=*pSrc;
 pDst+=Md->capture.internalChannels;
 pSrc+=1;
}
}
}
ma_device_handle_backend_data_callback(Md,NULL,Md->jack.pIntermediaryBufferCapture,frameCount);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_device_handle_backend_data_callback(Md,Md->jack.pIntermediaryBufferPlayback,NULL,frameCount);
for (iChannel=0; iChannel<Md->playback.internalChannels;++iChannel) {
float*pDst=(float*)((ma_jack_port_get_buffer_proc)Mc->jack.jack_port_get_buffer)((ma_jack_port_t*)Md->jack.ppPortsPlayback[iChannel],frameCount);
if (pDst !=NULL) {
const float*pSrc=Md->jack.pIntermediaryBufferPlayback+iChannel;
ma_jack_nframes_t iFrame;
for (iFrame=0; iFrame<frameCount;++iFrame) {
*pDst=*pSrc;
 pDst+=1;
 pSrc+=Md->playback.internalChannels;
}
}
}
}
Mr 0;
}
static Me ma_device_init__jack(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
M3 periodSizeInFrames;
MA_ASSERT(Mo !=NULL);
MA_ASSERT(Md !=NULL);
if (Mo->deviceType==ma_device_type_loopback) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Loopback mode not supported.");
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->pDeviceID !=NULL&&Mp->pDeviceID->jack !=0)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->pDeviceID !=NULL&&pDescriptorCapture->pDeviceID->jack !=0)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Only default devices are supported.");
Mr MA_NO_DEVICE;
}
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->shareMode==ma_share_mode_exclusive)) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Exclusive mode not supported.");
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
Mf=ma_context_open_client__jack(Md->Mc,(ma_jack_client_t**)&Md->jack.pClient);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.");
Mr Mf;
}
if (((ma_jack_set_process_callback_proc)Md->Mc->jack.jack_set_process_callback)((ma_jack_client_t*)Md->jack.pClient,ma_device__jack_process_callback,Md) !=0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
if (((ma_jack_set_buffer_size_callback_proc)Md->Mc->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)Md->jack.pClient,ma_device__jack_buffer_size_callback,Md) !=0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
((ma_jack_on_shutdown_proc)Md->Mc->jack.jack_on_shutdown)((ma_jack_client_t*)Md->jack.pClient,ma_device__jack_shutdown_callback,Md);
periodSizeInFrames=((ma_jack_get_buffer_size_proc)Md->Mc->jack.jack_get_buffer_size)((ma_jack_client_t*)Md->jack.pClient);
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
M3 iPort;
const char**ppPorts;
pDescriptorCapture->format=ma_format_f32;
pDescriptorCapture->Mh=0;
pDescriptorCapture->sampleRate=((ma_jack_get_sample_rate_proc)Md->Mc->jack.jack_get_sample_rate)((ma_jack_client_t*)Md->jack.pClient);
ma_channel_map_init_standard(ma_standard_channel_map_alsa,pDescriptorCapture->channelMap,ma_countof(pDescriptorCapture->channelMap),pDescriptorCapture->Mh);
ppPorts=((ma_jack_get_ports_proc)Md->Mc->jack.jack_get_ports)((ma_jack_client_t*)Md->jack.pClient,NULL,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsPhysical|ma_JackPortIsOutput);
if (ppPorts==NULL) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
while (ppPorts[pDescriptorCapture->Mh] !=NULL) {
pDescriptorCapture->Mh+=1;
}
Md->jack.ppPortsCapture=(ma_ptr*)ma_malloc(sizeof(*Md->jack.ppPortsCapture)*pDescriptorCapture->Mh,&Md->Mc->allocationCallbacks);
if (Md->jack.ppPortsCapture==NULL) {
Mr MA_OUT_OF_MEMORY;
}
for (iPort=0; iPort<pDescriptorCapture->Mh; iPort+=1) {
char name[64];
ma_strcpy_s(name, sizeof(name), "capture");
ma_itoa_s((int)iPort,name+7,sizeof(name)-7,10);
Md->jack.ppPortsCapture[iPort]=((ma_jack_port_register_proc)Md->Mc->jack.jack_port_register)((ma_jack_client_t*)Md->jack.pClient,name,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsInput,0);
if (Md->jack.ppPortsCapture[iPort]==NULL) {
((ma_jack_free_proc)Md->Mc->jack.jack_free)((Mv*)ppPorts);
ma_device_uninit__jack(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
}
((ma_jack_free_proc)Md->Mc->jack.jack_free)((Mv*)ppPorts);
pDescriptorCapture->periodSizeInFrames=periodSizeInFrames;
pDescriptorCapture->periodCount=1;
Md->jack.pIntermediaryBufferCapture=(float*)ma_calloc(pDescriptorCapture->periodSizeInFrames*ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh),&Md->Mc->allocationCallbacks);
if (Md->jack.pIntermediaryBufferCapture==NULL) {
ma_device_uninit__jack(Md);
Mr MA_OUT_OF_MEMORY;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
M3 iPort;
const char**ppPorts;
Mp->format=ma_format_f32;
Mp->Mh=0;
Mp->sampleRate=((ma_jack_get_sample_rate_proc)Md->Mc->jack.jack_get_sample_rate)((ma_jack_client_t*)Md->jack.pClient);
ma_channel_map_init_standard(ma_standard_channel_map_alsa,Mp->channelMap,ma_countof(Mp->channelMap),Mp->Mh);
ppPorts=((ma_jack_get_ports_proc)Md->Mc->jack.jack_get_ports)((ma_jack_client_t*)Md->jack.pClient,NULL,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsPhysical|ma_JackPortIsInput);
if (ppPorts==NULL) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
while (ppPorts[Mp->Mh] !=NULL) {
Mp->Mh+=1;
}
Md->jack.ppPortsPlayback=(ma_ptr*)ma_malloc(sizeof(*Md->jack.ppPortsPlayback)*Mp->Mh,&Md->Mc->allocationCallbacks);
if (Md->jack.ppPortsPlayback==NULL) {
ma_free(Md->jack.ppPortsCapture,&Md->Mc->allocationCallbacks);
Mr MA_OUT_OF_MEMORY;
}
for (iPort=0; iPort<Mp->Mh; iPort+=1) {
char name[64];
ma_strcpy_s(name, sizeof(name), "playback");
ma_itoa_s((int)iPort,name+8,sizeof(name)-8,10);
Md->jack.ppPortsPlayback[iPort]=((ma_jack_port_register_proc)Md->Mc->jack.jack_port_register)((ma_jack_client_t*)Md->jack.pClient,name,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsOutput,0);
if (Md->jack.ppPortsPlayback[iPort]==NULL) {
((ma_jack_free_proc)Md->Mc->jack.jack_free)((Mv*)ppPorts);
ma_device_uninit__jack(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
}
((ma_jack_free_proc)Md->Mc->jack.jack_free)((Mv*)ppPorts);
Mp->periodSizeInFrames=periodSizeInFrames;
Mp->periodCount=1;
Md->jack.pIntermediaryBufferPlayback=(float*)ma_calloc(Mp->periodSizeInFrames*ma_get_bytes_per_frame(Mp->format,Mp->Mh),&Md->Mc->allocationCallbacks);
if (Md->jack.pIntermediaryBufferPlayback==NULL) {
ma_device_uninit__jack(Md);
Mr MA_OUT_OF_MEMORY;
}
}
Mr Ms;
}
static Me ma_device_start__jack(ma_device*Md)
{
ma_context*Mc=Md->Mc;
int resultJACK;
size_t i;
resultJACK=((ma_jack_activate_proc)Mc->jack.jack_activate)((ma_jack_client_t*)Md->jack.pClient);
if (resultJACK !=0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.");
Mr MA_FAILED_TO_START_BACKEND_DEVICE;
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
const char**ppServerPorts=((ma_jack_get_ports_proc)Mc->jack.jack_get_ports)((ma_jack_client_t*)Md->jack.pClient,NULL,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsPhysical|ma_JackPortIsOutput);
if (ppServerPorts==NULL) {
((ma_jack_deactivate_proc)Mc->jack.jack_deactivate)((ma_jack_client_t*)Md->jack.pClient);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.");
Mr MA_ERROR;
}
for (i=0; ppServerPorts[i] !=NULL;++i) {
const char*pServerPort=ppServerPorts[i];
const char*pClientPort=((ma_jack_port_name_proc)Mc->jack.jack_port_name)((ma_jack_port_t*)Md->jack.ppPortsCapture[i]);
resultJACK=((ma_jack_connect_proc)Mc->jack.jack_connect)((ma_jack_client_t*)Md->jack.pClient,pServerPort,pClientPort);
if (resultJACK !=0) {
((ma_jack_free_proc)Mc->jack.jack_free)((Mv*)ppServerPorts);
((ma_jack_deactivate_proc)Mc->jack.jack_deactivate)((ma_jack_client_t*)Md->jack.pClient);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.");
Mr MA_ERROR;
}
}
((ma_jack_free_proc)Mc->jack.jack_free)((Mv*)ppServerPorts);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
const char**ppServerPorts=((ma_jack_get_ports_proc)Mc->jack.jack_get_ports)((ma_jack_client_t*)Md->jack.pClient,NULL,MA_JACK_DEFAULT_AUDIO_TYPE,ma_JackPortIsPhysical|ma_JackPortIsInput);
if (ppServerPorts==NULL) {
((ma_jack_deactivate_proc)Mc->jack.jack_deactivate)((ma_jack_client_t*)Md->jack.pClient);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.");
Mr MA_ERROR;
}
for (i=0; ppServerPorts[i] !=NULL;++i) {
const char*pServerPort=ppServerPorts[i];
const char*pClientPort=((ma_jack_port_name_proc)Mc->jack.jack_port_name)((ma_jack_port_t*)Md->jack.ppPortsPlayback[i]);
resultJACK=((ma_jack_connect_proc)Mc->jack.jack_connect)((ma_jack_client_t*)Md->jack.pClient,pClientPort,pServerPort);
if (resultJACK !=0) {
((ma_jack_free_proc)Mc->jack.jack_free)((Mv*)ppServerPorts);
((ma_jack_deactivate_proc)Mc->jack.jack_deactivate)((ma_jack_client_t*)Md->jack.pClient);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.");
Mr MA_ERROR;
}
}
((ma_jack_free_proc)Mc->jack.jack_free)((Mv*)ppServerPorts);
}
Mr Ms;
}
static Me ma_device_stop__jack(ma_device*Md)
{
ma_context*Mc=Md->Mc;
if (((ma_jack_deactivate_proc)Mc->jack.jack_deactivate)((ma_jack_client_t*)Md->jack.pClient) !=0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.");
Mr MA_ERROR;
}
ma_device__on_notification_stopped(Md);
Mr Ms;
}
static Me ma_context_uninit__jack(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_jack);
ma_free(Mc->jack.pClientName,&Mc->allocationCallbacks);
Mc->jack.pClientName=NULL;
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(ma_context_get_log(Mc),Mc->jack.jackSO);
#endif
Mr Ms;
}
static Me ma_context_init__jack(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
#ifndef MA_NO_RUNTIME_LINKING
const char*libjackNames[]={
#if defined(MA_WIN32)
"libjack.dll","libjack64.dll"
#endif
#if defined(MA_UNIX)
"libjack.so","libjack.so.0"
#endif
};
size_t i;
for (i=0; i<ma_countof(libjackNames);++i) {
Mc->jack.jackSO=ma_dlopen(ma_context_get_log(Mc),libjackNames[i]);
if (Mc->jack.jackSO !=NULL) {
break;
}
}
if (Mc->jack.jackSO==NULL) {
Mr MA_NO_BACKEND;
}
Mc->jack.jack_client_open = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_client_open");
Mc->jack.jack_client_close = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_client_close");
Mc->jack.jack_client_name_size = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_client_name_size");
Mc->jack.jack_set_process_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_set_process_callback");
Mc->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_set_buffer_size_callback");
Mc->jack.jack_on_shutdown = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_on_shutdown");
Mc->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_get_sample_rate");
Mc->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_get_buffer_size");
Mc->jack.jack_get_ports = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_get_ports");
Mc->jack.jack_activate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_activate");
Mc->jack.jack_deactivate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_deactivate");
Mc->jack.jack_connect = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_connect");
Mc->jack.jack_port_register = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_port_register");
Mc->jack.jack_port_name = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_port_name");
Mc->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_port_get_buffer");
Mc->jack.jack_free = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->jack.jackSO, "jack_free");
#else
ma_jack_client_open_proc _jack_client_open=jack_client_open;
ma_jack_client_close_proc _jack_client_close=jack_client_close;
ma_jack_client_name_size_proc _jack_client_name_size=jack_client_name_size;
ma_jack_set_process_callback_proc _jack_set_process_callback=jack_set_process_callback;
ma_jack_set_buffer_size_callback_proc _jack_set_buffer_size_callback=jack_set_buffer_size_callback;
ma_jack_on_shutdown_proc _jack_on_shutdown=jack_on_shutdown;
ma_jack_get_sample_rate_proc _jack_get_sample_rate=jack_get_sample_rate;
ma_jack_get_buffer_size_proc _jack_get_buffer_size=jack_get_buffer_size;
ma_jack_get_ports_proc _jack_get_ports=jack_get_ports;
ma_jack_activate_proc _jack_activate=jack_activate;
ma_jack_deactivate_proc _jack_deactivate=jack_deactivate;
ma_jack_connect_proc _jack_connect=jack_connect;
ma_jack_port_register_proc _jack_port_register=jack_port_register;
ma_jack_port_name_proc _jack_port_name=jack_port_name;
ma_jack_port_get_buffer_proc _jack_port_get_buffer=jack_port_get_buffer;
ma_jack_free_proc _jack_free=jack_free;
Mc->jack.jack_client_open=(ma_proc)_jack_client_open;
Mc->jack.jack_client_close=(ma_proc)_jack_client_close;
Mc->jack.jack_client_name_size=(ma_proc)_jack_client_name_size;
Mc->jack.jack_set_process_callback=(ma_proc)_jack_set_process_callback;
Mc->jack.jack_set_buffer_size_callback=(ma_proc)_jack_set_buffer_size_callback;
Mc->jack.jack_on_shutdown=(ma_proc)_jack_on_shutdown;
Mc->jack.jack_get_sample_rate=(ma_proc)_jack_get_sample_rate;
Mc->jack.jack_get_buffer_size=(ma_proc)_jack_get_buffer_size;
Mc->jack.jack_get_ports=(ma_proc)_jack_get_ports;
Mc->jack.jack_activate=(ma_proc)_jack_activate;
Mc->jack.jack_deactivate=(ma_proc)_jack_deactivate;
Mc->jack.jack_connect=(ma_proc)_jack_connect;
Mc->jack.jack_port_register=(ma_proc)_jack_port_register;
Mc->jack.jack_port_name=(ma_proc)_jack_port_name;
Mc->jack.jack_port_get_buffer=(ma_proc)_jack_port_get_buffer;
Mc->jack.jack_free=(ma_proc)_jack_free;
#endif
if (Mo->jack.pClientName !=NULL) {
Mc->jack.pClientName=ma_copy_string(Mo->jack.pClientName,&Mc->allocationCallbacks);
}
Mc->jack.tryStartServer=Mo->jack.tryStartServer;
{
ma_jack_client_t*pDummyClient;
Me Mf=ma_context_open_client__jack(Mc,&pDummyClient);
if (Mf !=Ms) {
ma_free(Mc->jack.pClientName,&Mc->allocationCallbacks);
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(ma_context_get_log(Mc),Mc->jack.jackSO);
#endif
Mr MA_NO_BACKEND;
}
((ma_jack_client_close_proc)Mc->jack.jack_client_close)((ma_jack_client_t*)pDummyClient);
}
pCallbacks->onContextInit=ma_context_init__jack;
pCallbacks->onContextUninit=ma_context_uninit__jack;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__jack;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__jack;
pCallbacks->onDeviceInit=ma_device_init__jack;
pCallbacks->onDeviceUninit=ma_device_uninit__jack;
pCallbacks->onDeviceStart=ma_device_start__jack;
pCallbacks->onDeviceStop=ma_device_stop__jack;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#ifdef MA_HAS_COREAUDIO
#include <TargetConditionals.h>
#if defined(TARGET_OS_IPHONE)&&TARGET_OS_IPHONE==1
#define MA_APPLE_MOBILE
#if defined(TARGET_OS_TV)&&TARGET_OS_TV==1
#define MA_APPLE_TV
#endif
#if defined(TARGET_OS_WATCH)&&TARGET_OS_WATCH==1
#define MA_APPLE_WATCH
#endif
#if __has_feature(objc_arc)
#define MA_BRIDGE_TRANSFER __bridge_transfer
#define MA_BRIDGE_RETAINED __bridge_retained
#else
#define MA_BRIDGE_TRANSFER
#define MA_BRIDGE_RETAINED
#endif
#else
#define MA_APPLE_DESKTOP
#endif
#if defined(MA_APPLE_DESKTOP)
#include <CoreAudio/CoreAudio.h>
#else
#include <AVFoundation/AVFoundation.h>
#endif
#include <AudioToolbox/AudioToolbox.h>
typedef Boolean (*ma_CFStringGetCString_proc)(CFStringRef theString,char*buffer,CFIndex bufferSize,CFStringEncoding encoding);
typedef Mv (*ma_CFRelease_proc)(CFTypeRef cf);
#if defined(MA_APPLE_DESKTOP)
typedef OSStatus (*ma_AudioObjectGetPropertyData_proc)(AudioObjectID inObjectID,const AudioObjectPropertyAddress*inAddress,UInt32 inQualifierDataSize,const Mv*inQualifierData,UInt32*ioDataSize,Mv*outData);
typedef OSStatus (*ma_AudioObjectGetPropertyDataSize_proc)(AudioObjectID inObjectID,const AudioObjectPropertyAddress*inAddress,UInt32 inQualifierDataSize,const Mv*inQualifierData,UInt32*outDataSize);
typedef OSStatus (*ma_AudioObjectSetPropertyData_proc)(AudioObjectID inObjectID,const AudioObjectPropertyAddress*inAddress,UInt32 inQualifierDataSize,const Mv*inQualifierData,UInt32 inDataSize,const Mv*inData);
typedef OSStatus (*ma_AudioObjectAddPropertyListener_proc)(AudioObjectID inObjectID,const AudioObjectPropertyAddress*inAddress,AudioObjectPropertyListenerProc inListener,Mv*inClientData);
typedef OSStatus (*ma_AudioObjectRemovePropertyListener_proc)(AudioObjectID inObjectID,const AudioObjectPropertyAddress*inAddress,AudioObjectPropertyListenerProc inListener,Mv*inClientData);
#endif
typedef AudioComponent (*ma_AudioComponentFindNext_proc)(AudioComponent inComponent,const AudioComponentDescription*inDesc);
typedef OSStatus (*ma_AudioComponentInstanceDispose_proc)(AudioComponentInstance inInstance);
typedef OSStatus (*ma_AudioComponentInstanceNew_proc)(AudioComponent inComponent,AudioComponentInstance*outInstance);
typedef OSStatus (*ma_AudioOutputUnitStart_proc)(AudioUnit inUnit);
typedef OSStatus (*ma_AudioOutputUnitStop_proc)(AudioUnit inUnit);
typedef OSStatus (*ma_AudioUnitAddPropertyListener_proc)(AudioUnit inUnit,AudioUnitPropertyID inID,AudioUnitPropertyListenerProc inProc,Mv*inProcUserData);
typedef OSStatus (*ma_AudioUnitGetPropertyInfo_proc)(AudioUnit inUnit,AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,UInt32*outDataSize,Boolean*outWriteable);
typedef OSStatus (*ma_AudioUnitGetProperty_proc)(AudioUnit inUnit,AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,Mv*outData,UInt32*ioDataSize);
typedef OSStatus (*ma_AudioUnitSetProperty_proc)(AudioUnit inUnit,AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,const Mv*inData,UInt32 inDataSize);
typedef OSStatus (*ma_AudioUnitInitialize_proc)(AudioUnit inUnit);
typedef OSStatus (*ma_AudioUnitRender_proc)(AudioUnit inUnit,AudioUnitRenderActionFlags*ioActionFlags,const AudioTimeStamp*inTimeStamp,UInt32 inOutputBusNumber,UInt32 inNumberFrames,AudioBufferList*ioData);
#define MA_COREAUDIO_OUTPUT_BUS 0
#define MA_COREAUDIO_INPUT_BUS 1
#if defined(MA_APPLE_DESKTOP)
static Me ma_device_reinit_internal__coreaudio(ma_device*Md,ma_device_type deviceType,ma_bool32 disposePreviousAudioUnit);
#endif
#if defined(MA_APPLE_MOBILE)
static Mv ma_device__on_notification_interruption_began(ma_device*Md)
{
ma_device__on_notification(ma_device_notification_init(Md,ma_device_notification_type_interruption_began));
}
static Mv ma_device__on_notification_interruption_ended(ma_device*Md)
{
ma_device__on_notification(ma_device_notification_init(Md,ma_device_notification_type_interruption_ended));
}
#endif
static Me ma_result_from_OSStatus(OSStatus status)
{
switch (status)
{
case noErr:Mr Ms;
#if defined(MA_APPLE_DESKTOP)
case kAudioHardwareNotRunningError:Mr MA_DEVICE_NOT_STARTED;
case kAudioHardwareUnspecifiedError:Mr MA_ERROR;
case kAudioHardwareUnknownPropertyError:Mr MA_INVALID_ARGS;
case kAudioHardwareBadPropertySizeError:Mr MA_INVALID_OPERATION;
case kAudioHardwareIllegalOperationError:Mr MA_INVALID_OPERATION;
case kAudioHardwareBadObjectError:Mr MA_INVALID_ARGS;
case kAudioHardwareBadDeviceError:Mr MA_INVALID_ARGS;
case kAudioHardwareBadStreamError:Mr MA_INVALID_ARGS;
case kAudioHardwareUnsupportedOperationError:Mr MA_INVALID_OPERATION;
case kAudioDeviceUnsupportedFormatError:Mr MA_FORMAT_NOT_SUPPORTED;
case kAudioDevicePermissionsError:Mr MA_ACCESS_DENIED;
#endif
default:Mr MA_ERROR;
}
}
#if 0
static ma_channel ma_channel_from_AudioChannelBitmap(AudioChannelBitmap bit)
{
switch (bit)
{
case kAudioChannelBit_Left:Mr MA_CHANNEL_LEFT;
case kAudioChannelBit_Right:Mr MA_CHANNEL_RIGHT;
case kAudioChannelBit_Center:Mr MA_CHANNEL_FRONT_CENTER;
case kAudioChannelBit_LFEScreen:Mr MA_CHANNEL_LFE;
case kAudioChannelBit_LeftSurround:Mr MA_CHANNEL_BACK_LEFT;
case kAudioChannelBit_RightSurround:Mr MA_CHANNEL_BACK_RIGHT;
case kAudioChannelBit_LeftCenter:Mr MA_CHANNEL_FRONT_LEFT_CENTER;
case kAudioChannelBit_RightCenter:Mr MA_CHANNEL_FRONT_RIGHT_CENTER;
case kAudioChannelBit_CenterSurround:Mr MA_CHANNEL_BACK_CENTER;
case kAudioChannelBit_LeftSurroundDirect:Mr MA_CHANNEL_SIDE_LEFT;
case kAudioChannelBit_RightSurroundDirect:Mr MA_CHANNEL_SIDE_RIGHT;
case kAudioChannelBit_TopCenterSurround:Mr MA_CHANNEL_TOP_CENTER;
case kAudioChannelBit_VerticalHeightLeft:Mr MA_CHANNEL_TOP_FRONT_LEFT;
case kAudioChannelBit_VerticalHeightCenter:Mr MA_CHANNEL_TOP_FRONT_CENTER;
case kAudioChannelBit_VerticalHeightRight:Mr MA_CHANNEL_TOP_FRONT_RIGHT;
case kAudioChannelBit_TopBackLeft:Mr MA_CHANNEL_TOP_BACK_LEFT;
case kAudioChannelBit_TopBackCenter:Mr MA_CHANNEL_TOP_BACK_CENTER;
case kAudioChannelBit_TopBackRight:Mr MA_CHANNEL_TOP_BACK_RIGHT;
default:Mr MA_CHANNEL_NONE;
}
}
#endif
static Me ma_format_from_AudioStreamBasicDescription(const AudioStreamBasicDescription*pDescription,ma_format*pFormatOut)
{
MA_ASSERT(pDescription !=NULL);
MA_ASSERT(pFormatOut !=NULL);
*pFormatOut=ma_format_unknown;
if (pDescription->mFormatID !=kAudioFormatLinearPCM) {
Mr MA_FORMAT_NOT_SUPPORTED;
}
if ((pDescription->mFormatFlags&kLinearPCMFormatFlagIsAlignedHigh) !=0) {
Mr MA_FORMAT_NOT_SUPPORTED;
}
if ((ma_is_little_endian()&&(pDescription->mFormatFlags&kAudioFormatFlagIsBigEndian) !=0)||(ma_is_big_endian()&&(pDescription->mFormatFlags&kAudioFormatFlagIsBigEndian)==0)) {
Mr MA_FORMAT_NOT_SUPPORTED;
}
if ((pDescription->mFormatFlags&kLinearPCMFormatFlagIsFloat) !=0) {
if (pDescription->mBitsPerChannel==32) {
*pFormatOut=ma_format_f32;
Mr Ms;
}
} else {
if ((pDescription->mFormatFlags&kLinearPCMFormatFlagIsSignedInteger) !=0) {
if (pDescription->mBitsPerChannel==16) {
*pFormatOut=ma_format_s16;
Mr Ms;
} else if (pDescription->mBitsPerChannel==24) {
if (pDescription->mBytesPerFrame==(pDescription->mBitsPerChannel/8*pDescription->mChannelsPerFrame)) {
*pFormatOut=ma_format_s24;
 Mr Ms;
} else {
 if (pDescription->mBytesPerFrame/pDescription->mChannelsPerFrame==sizeof(ma_int32)) {
 Mr MA_FORMAT_NOT_SUPPORTED;
 }
}
} else if (pDescription->mBitsPerChannel==32) {
*pFormatOut=ma_format_s32;
Mr Ms;
}
} else {
if (pDescription->mBitsPerChannel==8) {
*pFormatOut=ma_format_u8;
Mr Ms;
}
}
}
Mr MA_FORMAT_NOT_SUPPORTED;
}
#if defined(MA_APPLE_DESKTOP)
static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label)
{
switch (label)
{
case kAudioChannelLabel_Unknown:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Unused:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_UseCoordinates:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Left:Mr MA_CHANNEL_LEFT;
case kAudioChannelLabel_Right:Mr MA_CHANNEL_RIGHT;
case kAudioChannelLabel_Center:Mr MA_CHANNEL_FRONT_CENTER;
case kAudioChannelLabel_LFEScreen:Mr MA_CHANNEL_LFE;
case kAudioChannelLabel_LeftSurround:Mr MA_CHANNEL_BACK_LEFT;
case kAudioChannelLabel_RightSurround:Mr MA_CHANNEL_BACK_RIGHT;
case kAudioChannelLabel_LeftCenter:Mr MA_CHANNEL_FRONT_LEFT_CENTER;
case kAudioChannelLabel_RightCenter:Mr MA_CHANNEL_FRONT_RIGHT_CENTER;
case kAudioChannelLabel_CenterSurround:Mr MA_CHANNEL_BACK_CENTER;
case kAudioChannelLabel_LeftSurroundDirect:Mr MA_CHANNEL_SIDE_LEFT;
case kAudioChannelLabel_RightSurroundDirect:Mr MA_CHANNEL_SIDE_RIGHT;
case kAudioChannelLabel_TopCenterSurround:Mr MA_CHANNEL_TOP_CENTER;
case kAudioChannelLabel_VerticalHeightLeft:Mr MA_CHANNEL_TOP_FRONT_LEFT;
case kAudioChannelLabel_VerticalHeightCenter:Mr MA_CHANNEL_TOP_FRONT_CENTER;
case kAudioChannelLabel_VerticalHeightRight:Mr MA_CHANNEL_TOP_FRONT_RIGHT;
case kAudioChannelLabel_TopBackLeft:Mr MA_CHANNEL_TOP_BACK_LEFT;
case kAudioChannelLabel_TopBackCenter:Mr MA_CHANNEL_TOP_BACK_CENTER;
case kAudioChannelLabel_TopBackRight:Mr MA_CHANNEL_TOP_BACK_RIGHT;
case kAudioChannelLabel_RearSurroundLeft:Mr MA_CHANNEL_BACK_LEFT;
case kAudioChannelLabel_RearSurroundRight:Mr MA_CHANNEL_BACK_RIGHT;
case kAudioChannelLabel_LeftWide:Mr MA_CHANNEL_SIDE_LEFT;
case kAudioChannelLabel_RightWide:Mr MA_CHANNEL_SIDE_RIGHT;
case kAudioChannelLabel_LFE2:Mr MA_CHANNEL_LFE;
case kAudioChannelLabel_LeftTotal:Mr MA_CHANNEL_LEFT;
case kAudioChannelLabel_RightTotal:Mr MA_CHANNEL_RIGHT;
case kAudioChannelLabel_HearingImpaired:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Narration:Mr MA_CHANNEL_MONO;
case kAudioChannelLabel_Mono:Mr MA_CHANNEL_MONO;
case kAudioChannelLabel_DialogCentricMix:Mr MA_CHANNEL_MONO;
case kAudioChannelLabel_CenterSurroundDirect:Mr MA_CHANNEL_BACK_CENTER;
case kAudioChannelLabel_Haptic:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Ambisonic_W:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Ambisonic_X:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Ambisonic_Y:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Ambisonic_Z:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_MS_Mid:Mr MA_CHANNEL_LEFT;
case kAudioChannelLabel_MS_Side:Mr MA_CHANNEL_RIGHT;
case kAudioChannelLabel_XY_X:Mr MA_CHANNEL_LEFT;
case kAudioChannelLabel_XY_Y:Mr MA_CHANNEL_RIGHT;
case kAudioChannelLabel_HeadphonesLeft:Mr MA_CHANNEL_LEFT;
case kAudioChannelLabel_HeadphonesRight:Mr MA_CHANNEL_RIGHT;
case kAudioChannelLabel_ClickTrack:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_ForeignLanguage:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Discrete:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_Discrete_0:Mr MA_CHANNEL_AUX_0;
case kAudioChannelLabel_Discrete_1:Mr MA_CHANNEL_AUX_1;
case kAudioChannelLabel_Discrete_2:Mr MA_CHANNEL_AUX_2;
case kAudioChannelLabel_Discrete_3:Mr MA_CHANNEL_AUX_3;
case kAudioChannelLabel_Discrete_4:Mr MA_CHANNEL_AUX_4;
case kAudioChannelLabel_Discrete_5:Mr MA_CHANNEL_AUX_5;
case kAudioChannelLabel_Discrete_6:Mr MA_CHANNEL_AUX_6;
case kAudioChannelLabel_Discrete_7:Mr MA_CHANNEL_AUX_7;
case kAudioChannelLabel_Discrete_8:Mr MA_CHANNEL_AUX_8;
case kAudioChannelLabel_Discrete_9:Mr MA_CHANNEL_AUX_9;
case kAudioChannelLabel_Discrete_10:Mr MA_CHANNEL_AUX_10;
case kAudioChannelLabel_Discrete_11:Mr MA_CHANNEL_AUX_11;
case kAudioChannelLabel_Discrete_12:Mr MA_CHANNEL_AUX_12;
case kAudioChannelLabel_Discrete_13:Mr MA_CHANNEL_AUX_13;
case kAudioChannelLabel_Discrete_14:Mr MA_CHANNEL_AUX_14;
case kAudioChannelLabel_Discrete_15:Mr MA_CHANNEL_AUX_15;
case kAudioChannelLabel_Discrete_65535:Mr MA_CHANNEL_NONE;
#if 0
case kAudioChannelLabel_HOA_ACN:Mr MA_CHANNEL_NONE;
case kAudioChannelLabel_HOA_ACN_0:Mr MA_CHANNEL_AUX_0;
case kAudioChannelLabel_HOA_ACN_1:Mr MA_CHANNEL_AUX_1;
case kAudioChannelLabel_HOA_ACN_2:Mr MA_CHANNEL_AUX_2;
case kAudioChannelLabel_HOA_ACN_3:Mr MA_CHANNEL_AUX_3;
case kAudioChannelLabel_HOA_ACN_4:Mr MA_CHANNEL_AUX_4;
case kAudioChannelLabel_HOA_ACN_5:Mr MA_CHANNEL_AUX_5;
case kAudioChannelLabel_HOA_ACN_6:Mr MA_CHANNEL_AUX_6;
case kAudioChannelLabel_HOA_ACN_7:Mr MA_CHANNEL_AUX_7;
case kAudioChannelLabel_HOA_ACN_8:Mr MA_CHANNEL_AUX_8;
case kAudioChannelLabel_HOA_ACN_9:Mr MA_CHANNEL_AUX_9;
case kAudioChannelLabel_HOA_ACN_10:Mr MA_CHANNEL_AUX_10;
case kAudioChannelLabel_HOA_ACN_11:Mr MA_CHANNEL_AUX_11;
case kAudioChannelLabel_HOA_ACN_12:Mr MA_CHANNEL_AUX_12;
case kAudioChannelLabel_HOA_ACN_13:Mr MA_CHANNEL_AUX_13;
case kAudioChannelLabel_HOA_ACN_14:Mr MA_CHANNEL_AUX_14;
case kAudioChannelLabel_HOA_ACN_15:Mr MA_CHANNEL_AUX_15;
case kAudioChannelLabel_HOA_ACN_65024:Mr MA_CHANNEL_NONE;
#endif
default:Mr MA_CHANNEL_NONE;
}
}
static Me ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout*pChannelLayout,ma_channel*pChannelMap,size_t channelMapCap)
{
MA_ASSERT(pChannelLayout !=NULL);
if (pChannelLayout->mChannelLayoutTag==kAudioChannelLayoutTag_UseChannelDescriptions) {
UInt32 iChannel;
for (iChannel=0; iChannel<pChannelLayout->mNumberChannelDescriptions&&iChannel<channelMapCap;++iChannel) {
pChannelMap[iChannel]=ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel);
}
} else
#if 0
if (pChannelLayout->mChannelLayoutTag==kAudioChannelLayoutTag_UseChannelBitmap) {
UInt32 iChannel=0;
UInt32 iBit;
AudioChannelBitmap bitmap=pChannelLayout->mChannelBitmap;
for (iBit=0; iBit<32&&iChannel<channelMapCap;++iBit) {
AudioChannelBitmap bit=bitmap&(1<<iBit);
if (bit !=0) {
pChannelMap[iChannel++]=ma_channel_from_AudioChannelBit(bit);
}
}
} else
#endif
{
UInt32 channelCount;
if (channelMapCap>0xFFFFFFFF) {
channelMapCap=0xFFFFFFFF;
}
channelCount=ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag),(UInt32)channelMapCap);
switch (pChannelLayout->mChannelLayoutTag)
{
case kAudioChannelLayoutTag_Mono:
case kAudioChannelLayoutTag_Stereo:
case kAudioChannelLayoutTag_StereoHeadphones:
case kAudioChannelLayoutTag_MatrixStereo:
case kAudioChannelLayoutTag_MidSide:
case kAudioChannelLayoutTag_XY:
case kAudioChannelLayoutTag_Binaural:
case kAudioChannelLayoutTag_Ambisonic_B_Format:
{
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,channelCount);
} break;
case kAudioChannelLayoutTag_Octagonal:
{
pChannelMap[7]=MA_CHANNEL_SIDE_RIGHT;
pChannelMap[6]=MA_CHANNEL_SIDE_LEFT;
} MA_FALLTHROUGH;
case kAudioChannelLayoutTag_Hexagonal:
{
pChannelMap[5]=MA_CHANNEL_BACK_CENTER;
} MA_FALLTHROUGH;
case kAudioChannelLayoutTag_Pentagonal:
{
pChannelMap[4]=MA_CHANNEL_FRONT_CENTER;
} MA_FALLTHROUGH;
case kAudioChannelLayoutTag_Quadraphonic:
{
pChannelMap[3]=MA_CHANNEL_BACK_RIGHT;
pChannelMap[2]=MA_CHANNEL_BACK_LEFT;
pChannelMap[1]=MA_CHANNEL_RIGHT;
pChannelMap[0]=MA_CHANNEL_LEFT;
} break;
default:
{
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,channelCount);
} break;
}
}
Mr Ms;
}
#if (defined(MAC_OS_VERSION_12_0)&&MAC_OS_X_VERSION_MAX_ALLOWED>=MAC_OS_VERSION_12_0)||\
(defined(__IPHONE_15_0)&&__IPHONE_OS_VERSION_MAX_ALLOWED>=__IPHONE_15_0)
#define AUDIO_OBJECT_PROPERTY_ELEMENT kAudioObjectPropertyElementMain
#else
#define AUDIO_OBJECT_PROPERTY_ELEMENT kAudioObjectPropertyElementMaster
#endif
#if !defined(MAC_OS_X_VERSION_10_8)||(MAC_OS_X_VERSION_MIN_REQUIRED<MAC_OS_X_VERSION_10_8)
#define kAudioObjectPropertyScopeInput kAudioDevicePropertyScopeInput
#define kAudioObjectPropertyScopeOutput kAudioDevicePropertyScopeOutput
#endif
static Me ma_get_device_object_ids__coreaudio(ma_context*Mc,UInt32*pDeviceCount,AudioObjectID**ppDeviceObjectIDs)
{
AudioObjectPropertyAddress propAddressDevices;
UInt32 deviceObjectsDataSize;
OSStatus status;
AudioObjectID*pDeviceObjectIDs;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDeviceCount !=NULL);
MA_ASSERT(ppDeviceObjectIDs !=NULL);
*pDeviceCount=0;
*ppDeviceObjectIDs=NULL;
propAddressDevices.mSelector=kAudioHardwarePropertyDevices;
propAddressDevices.mScope=kAudioObjectPropertyScopeGlobal;
propAddressDevices.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
status=((ma_AudioObjectGetPropertyDataSize_proc)Mc->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject,&propAddressDevices,0,NULL,&deviceObjectsDataSize);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
pDeviceObjectIDs=(AudioObjectID*)ma_malloc(deviceObjectsDataSize,&Mc->allocationCallbacks);
if (pDeviceObjectIDs==NULL) {
Mr MA_OUT_OF_MEMORY;
}
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject,&propAddressDevices,0,NULL,&deviceObjectsDataSize,pDeviceObjectIDs);
if (status !=noErr) {
ma_free(pDeviceObjectIDs,&Mc->allocationCallbacks);
Mr ma_result_from_OSStatus(status);
}
*pDeviceCount=deviceObjectsDataSize / sizeof(AudioObjectID);
*ppDeviceObjectIDs=pDeviceObjectIDs;
Mr Ms;
}
static Me ma_get_AudioObject_uid_as_CFStringRef(ma_context*Mc,AudioObjectID objectID,CFStringRef*pUID)
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
MA_ASSERT(Mc !=NULL);
propAddress.mSelector=kAudioDevicePropertyDeviceUID;
propAddress.mScope=kAudioObjectPropertyScopeGlobal;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
dataSize=sizeof(*pUID);
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(objectID,&propAddress,0,NULL,&dataSize,pUID);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
Mr Ms;
}
static Me ma_get_AudioObject_uid(ma_context*Mc,AudioObjectID objectID,size_t bufferSize,char*bufferOut)
{
CFStringRef uid;
Me Mf;
MA_ASSERT(Mc !=NULL);
Mf=ma_get_AudioObject_uid_as_CFStringRef(Mc,objectID,&uid);
if (Mf !=Ms) {
Mr Mf;
}
if (!((ma_CFStringGetCString_proc)Mc->coreaudio.CFStringGetCString)(uid,bufferOut,bufferSize,kCFStringEncodingUTF8)) {
Mr MA_ERROR;
}
((ma_CFRelease_proc)Mc->coreaudio.CFRelease)(uid);
Mr Ms;
}
static Me ma_get_AudioObject_name(ma_context*Mc,AudioObjectID objectID,size_t bufferSize,char*bufferOut)
{
AudioObjectPropertyAddress propAddress;
CFStringRef deviceName=NULL;
UInt32 dataSize;
OSStatus status;
MA_ASSERT(Mc !=NULL);
propAddress.mSelector=kAudioDevicePropertyDeviceNameCFString;
propAddress.mScope=kAudioObjectPropertyScopeGlobal;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
dataSize=sizeof(deviceName);
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(objectID,&propAddress,0,NULL,&dataSize,&deviceName);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
if (!((ma_CFStringGetCString_proc)Mc->coreaudio.CFStringGetCString)(deviceName,bufferOut,bufferSize,kCFStringEncodingUTF8)) {
Mr MA_ERROR;
}
((ma_CFRelease_proc)Mc->coreaudio.CFRelease)(deviceName);
Mr Ms;
}
static ma_bool32 ma_does_AudioObject_support_scope(ma_context*Mc,AudioObjectID deviceObjectID,AudioObjectPropertyScope scope)
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
AudioBufferList*pBufferList;
ma_bool32 isSupported;
MA_ASSERT(Mc !=NULL);
propAddress.mSelector=kAudioDevicePropertyStreamConfiguration;
propAddress.mScope=scope;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
status=((ma_AudioObjectGetPropertyDataSize_proc)Mc->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID,&propAddress,0,NULL,&dataSize);
if (status !=noErr) {
Mr MA_FALSE;
}
pBufferList=(AudioBufferList*)ma_malloc(dataSize,&Mc->allocationCallbacks);
if (pBufferList==NULL) {
Mr MA_FALSE;
}
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(deviceObjectID,&propAddress,0,NULL,&dataSize,pBufferList);
if (status !=noErr) {
ma_free(pBufferList,&Mc->allocationCallbacks);
Mr MA_FALSE;
}
isSupported=MA_FALSE;
if (pBufferList->mNumberBuffers>0) {
isSupported=MA_TRUE;
}
ma_free(pBufferList,&Mc->allocationCallbacks);
Mr isSupported;
}
static ma_bool32 ma_does_AudioObject_support_playback(ma_context*Mc,AudioObjectID deviceObjectID)
{
Mr ma_does_AudioObject_support_scope(Mc,deviceObjectID,kAudioObjectPropertyScopeOutput);
}
static ma_bool32 ma_does_AudioObject_support_capture(ma_context*Mc,AudioObjectID deviceObjectID)
{
Mr ma_does_AudioObject_support_scope(Mc,deviceObjectID,kAudioObjectPropertyScopeInput);
}
static Me ma_get_AudioObject_stream_descriptions(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,UInt32*pDescriptionCount,AudioStreamRangedDescription**ppDescriptions)
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
AudioStreamRangedDescription*pDescriptions;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDescriptionCount !=NULL);
MA_ASSERT(ppDescriptions !=NULL);
propAddress.mSelector=kAudioStreamPropertyAvailableVirtualFormats;
propAddress.mScope=(deviceType==Mt)?kAudioObjectPropertyScopeOutput:kAudioObjectPropertyScopeInput;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
status=((ma_AudioObjectGetPropertyDataSize_proc)Mc->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID,&propAddress,0,NULL,&dataSize);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
pDescriptions=(AudioStreamRangedDescription*)ma_malloc(dataSize,&Mc->allocationCallbacks);
if (pDescriptions==NULL) {
Mr MA_OUT_OF_MEMORY;
}
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(deviceObjectID,&propAddress,0,NULL,&dataSize,pDescriptions);
if (status !=noErr) {
ma_free(pDescriptions,&Mc->allocationCallbacks);
Mr ma_result_from_OSStatus(status);
}
*pDescriptionCount=dataSize / sizeof(*pDescriptions);
*ppDescriptions=pDescriptions;
Mr Ms;
}
static Me ma_get_AudioObject_channel_layout(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,AudioChannelLayout**ppChannelLayout)
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
AudioChannelLayout*pChannelLayout;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(ppChannelLayout !=NULL);
*ppChannelLayout=NULL;
propAddress.mSelector=kAudioDevicePropertyPreferredChannelLayout;
propAddress.mScope=(deviceType==Mt)?kAudioObjectPropertyScopeOutput:kAudioObjectPropertyScopeInput;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
status=((ma_AudioObjectGetPropertyDataSize_proc)Mc->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID,&propAddress,0,NULL,&dataSize);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
pChannelLayout=(AudioChannelLayout*)ma_malloc(dataSize,&Mc->allocationCallbacks);
if (pChannelLayout==NULL) {
Mr MA_OUT_OF_MEMORY;
}
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(deviceObjectID,&propAddress,0,NULL,&dataSize,pChannelLayout);
if (status !=noErr) {
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr ma_result_from_OSStatus(status);
}
*ppChannelLayout=pChannelLayout;
Mr Ms;
}
static Me ma_get_AudioObject_channel_count(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,M3*pChannelCount)
{
AudioChannelLayout*pChannelLayout;
Me Mf;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pChannelCount !=NULL);
*pChannelCount=0;
Mf=ma_get_AudioObject_channel_layout(Mc,deviceObjectID,deviceType,&pChannelLayout);
if (Mf !=Ms) {
Mr Mf;
}
if (pChannelLayout->mChannelLayoutTag==kAudioChannelLayoutTag_UseChannelDescriptions) {
*pChannelCount=pChannelLayout->mNumberChannelDescriptions;
} else if (pChannelLayout->mChannelLayoutTag==kAudioChannelLayoutTag_UseChannelBitmap) {
*pChannelCount=ma_count_set_bits(pChannelLayout->mChannelBitmap);
} else {
*pChannelCount=AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag);
}
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr Ms;
}
#if 0
static Me ma_get_AudioObject_channel_map(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,ma_channel*pChannelMap,size_t channelMapCap)
{
AudioChannelLayout*pChannelLayout;
Me Mf;
MA_ASSERT(Mc !=NULL);
Mf=ma_get_AudioObject_channel_layout(Mc,deviceObjectID,deviceType,&pChannelLayout);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_get_channel_map_from_AudioChannelLayout(pChannelLayout,pChannelMap,channelMapCap);
if (Mf !=Ms) {
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr Mf;
}
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr Mf;
}
#endif
static Me ma_get_AudioObject_sample_rates(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,UInt32*pSampleRateRangesCount,AudioValueRange**ppSampleRateRanges)
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
AudioValueRange*pSampleRateRanges;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pSampleRateRangesCount !=NULL);
MA_ASSERT(ppSampleRateRanges !=NULL);
*pSampleRateRangesCount=0;
*ppSampleRateRanges=NULL;
propAddress.mSelector=kAudioDevicePropertyAvailableNominalSampleRates;
propAddress.mScope=(deviceType==Mt)?kAudioObjectPropertyScopeOutput:kAudioObjectPropertyScopeInput;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
status=((ma_AudioObjectGetPropertyDataSize_proc)Mc->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID,&propAddress,0,NULL,&dataSize);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
pSampleRateRanges=(AudioValueRange*)ma_malloc(dataSize,&Mc->allocationCallbacks);
if (pSampleRateRanges==NULL) {
Mr MA_OUT_OF_MEMORY;
}
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(deviceObjectID,&propAddress,0,NULL,&dataSize,pSampleRateRanges);
if (status !=noErr) {
ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
Mr ma_result_from_OSStatus(status);
}
*pSampleRateRangesCount=dataSize / sizeof(*pSampleRateRanges);
*ppSampleRateRanges=pSampleRateRanges;
Mr Ms;
}
#if 0
static Me ma_get_AudioObject_get_closest_sample_rate(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,M3 sampleRateIn,M3*pSampleRateOut)
{
UInt32 sampleRateRangeCount;
AudioValueRange*pSampleRateRanges;
Me Mf;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pSampleRateOut !=NULL);
*pSampleRateOut=0;
Mf=ma_get_AudioObject_sample_rates(Mc,deviceObjectID,deviceType,&sampleRateRangeCount,&pSampleRateRanges);
if (Mf !=Ms) {
Mr Mf;
}
if (sampleRateRangeCount==0) {
ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
Mr MA_ERROR;
}
if (sampleRateIn==0) {
UInt32 iMALSampleRate;
for (iMALSampleRate=0; iMALSampleRate<ma_countof(g_maStandardSampleRatePriorities);++iMALSampleRate) {
M3 malSampleRate=g_maStandardSampleRatePriorities[iMALSampleRate];
UInt32 iCASampleRate;
for (iCASampleRate=0; iCASampleRate<sampleRateRangeCount;++iCASampleRate) {
AudioValueRange caSampleRate=pSampleRateRanges[iCASampleRate];
if (caSampleRate.mMinimum<=malSampleRate&&caSampleRate.mMaximum>=malSampleRate) {
*pSampleRateOut=malSampleRate;
 ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
 Mr Ms;
}
}
}
MA_ASSERT(sampleRateRangeCount>0);
*pSampleRateOut=pSampleRateRanges[0].mMinimum;
ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
Mr Ms;
} else {
UInt32 currentAbsoluteDifference=INT32_MAX;
UInt32 iCurrentClosestRange=(UInt32)-1;
UInt32 iRange;
for (iRange=0; iRange<sampleRateRangeCount;++iRange) {
if (pSampleRateRanges[iRange].mMinimum<=sampleRateIn&&pSampleRateRanges[iRange].mMaximum>=sampleRateIn) {
*pSampleRateOut=sampleRateIn;
ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
Mr Ms;
} else {
UInt32 absoluteDifference;
if (pSampleRateRanges[iRange].mMinimum>sampleRateIn) {
 absoluteDifference=pSampleRateRanges[iRange].mMinimum-sampleRateIn;
} else {
 absoluteDifference=sampleRateIn-pSampleRateRanges[iRange].mMaximum;
}
if (currentAbsoluteDifference>absoluteDifference) {
 currentAbsoluteDifference=absoluteDifference;
 iCurrentClosestRange=iRange;
}
}
}
MA_ASSERT(iCurrentClosestRange !=(UInt32)-1);
*pSampleRateOut=pSampleRateRanges[iCurrentClosestRange].mMinimum;
ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
Mr Ms;
}
}
#endif
static Me ma_get_AudioObject_closest_buffer_size_in_frames(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,M3 bufferSizeInFramesIn,M3*pBufferSizeInFramesOut)
{
AudioObjectPropertyAddress propAddress;
AudioValueRange bufferSizeRange;
UInt32 dataSize;
OSStatus status;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pBufferSizeInFramesOut !=NULL);
*pBufferSizeInFramesOut=0;
propAddress.mSelector=kAudioDevicePropertyBufferFrameSizeRange;
propAddress.mScope=(deviceType==Mt)?kAudioObjectPropertyScopeOutput:kAudioObjectPropertyScopeInput;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
dataSize=sizeof(bufferSizeRange);
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(deviceObjectID,&propAddress,0,NULL,&dataSize,&bufferSizeRange);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
if (bufferSizeInFramesIn<bufferSizeRange.mMinimum) {
*pBufferSizeInFramesOut=(M3)bufferSizeRange.mMinimum;
} else if (bufferSizeInFramesIn>bufferSizeRange.mMaximum) {
*pBufferSizeInFramesOut=(M3)bufferSizeRange.mMaximum;
} else {
*pBufferSizeInFramesOut=bufferSizeInFramesIn;
}
Mr Ms;
}
static Me ma_set_AudioObject_buffer_size_in_frames(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,M3*pPeriodSizeInOut)
{
Me Mf;
M3 chosenBufferSizeInFrames;
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
MA_ASSERT(Mc !=NULL);
Mf=ma_get_AudioObject_closest_buffer_size_in_frames(Mc,deviceObjectID,deviceType,*pPeriodSizeInOut,&chosenBufferSizeInFrames);
if (Mf !=Ms) {
Mr Mf;
}
propAddress.mSelector=kAudioDevicePropertyBufferFrameSize;
propAddress.mScope=(deviceType==Mt)?kAudioObjectPropertyScopeOutput:kAudioObjectPropertyScopeInput;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
((ma_AudioObjectSetPropertyData_proc)Mc->coreaudio.AudioObjectSetPropertyData)(deviceObjectID,&propAddress,0,NULL,sizeof(chosenBufferSizeInFrames),&chosenBufferSizeInFrames);
dataSize=sizeof(*pPeriodSizeInOut);
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(deviceObjectID,&propAddress,0,NULL,&dataSize,&chosenBufferSizeInFrames);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
*pPeriodSizeInOut=chosenBufferSizeInFrames;
Mr Ms;
}
static Me ma_find_default_AudioObjectID(ma_context*Mc,ma_device_type deviceType,AudioObjectID*pDeviceObjectID)
{
AudioObjectPropertyAddress propAddressDefaultDevice;
UInt32 defaultDeviceObjectIDSize=sizeof(AudioObjectID);
AudioObjectID defaultDeviceObjectID;
OSStatus status;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDeviceObjectID !=NULL);
*pDeviceObjectID=0;
propAddressDefaultDevice.mScope=kAudioObjectPropertyScopeGlobal;
propAddressDefaultDevice.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
if (deviceType==Mt) {
propAddressDefaultDevice.mSelector=kAudioHardwarePropertyDefaultOutputDevice;
} else {
propAddressDefaultDevice.mSelector=kAudioHardwarePropertyDefaultInputDevice;
}
defaultDeviceObjectIDSize=sizeof(AudioObjectID);
status=((ma_AudioObjectGetPropertyData_proc)Mc->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject,&propAddressDefaultDevice,0,NULL,&defaultDeviceObjectIDSize,&defaultDeviceObjectID);
if (status==noErr) {
*pDeviceObjectID=defaultDeviceObjectID;
Mr Ms;
}
Mr MA_NO_DEVICE;
}
static Me ma_find_AudioObjectID(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,AudioObjectID*pDeviceObjectID)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDeviceObjectID !=NULL);
*pDeviceObjectID=0;
if (pDeviceID==NULL) {
Mr ma_find_default_AudioObjectID(Mc,deviceType,pDeviceObjectID);
} else {
UInt32 deviceCount;
AudioObjectID*pDeviceObjectIDs;
Me Mf;
UInt32 iDevice;
Mf=ma_get_device_object_ids__coreaudio(Mc,&deviceCount,&pDeviceObjectIDs);
if (Mf !=Ms) {
Mr Mf;
}
for (iDevice=0; iDevice<deviceCount;++iDevice) {
AudioObjectID deviceObjectID=pDeviceObjectIDs[iDevice];
char uid[256];
if (ma_get_AudioObject_uid(Mc,deviceObjectID,sizeof(uid),uid) !=Ms) {
continue;
}
if (deviceType==Mt) {
if (ma_does_AudioObject_support_playback(Mc,deviceObjectID)) {
 if (strcmp(uid,pDeviceID->coreaudio)==0) {
*pDeviceObjectID=deviceObjectID;
 ma_free(pDeviceObjectIDs,&Mc->allocationCallbacks);
 Mr Ms;
 }
}
} else {
if (ma_does_AudioObject_support_capture(Mc,deviceObjectID)) {
 if (strcmp(uid,pDeviceID->coreaudio)==0) {
*pDeviceObjectID=deviceObjectID;
 ma_free(pDeviceObjectIDs,&Mc->allocationCallbacks);
 Mr Ms;
 }
}
}
}
ma_free(pDeviceObjectIDs,&Mc->allocationCallbacks);
}
Mr MA_NO_DEVICE;
}
static Me ma_find_best_format__coreaudio(ma_context*Mc,AudioObjectID deviceObjectID,ma_device_type deviceType,ma_format format,M3 Mh,M3 sampleRate,const AudioStreamBasicDescription*pOrigFormat,AudioStreamBasicDescription*pFormat)
{
UInt32 deviceFormatDescriptionCount;
AudioStreamRangedDescription*pDeviceFormatDescriptions;
Me Mf;
M3 desiredSampleRate;
M3 desiredChannelCount;
ma_format desiredFormat;
AudioStreamBasicDescription bestDeviceFormatSoFar;
ma_bool32 hasSupportedFormat;
UInt32 iFormat;
Mf=ma_get_AudioObject_stream_descriptions(Mc,deviceObjectID,deviceType,&deviceFormatDescriptionCount,&pDeviceFormatDescriptions);
if (Mf !=Ms) {
Mr Mf;
}
desiredSampleRate=sampleRate;
if (desiredSampleRate==0) {
desiredSampleRate=(M3)pOrigFormat->mSampleRate;
}
desiredChannelCount=Mh;
if (desiredChannelCount==0) {
desiredChannelCount=pOrigFormat->mChannelsPerFrame;
}
desiredFormat=format;
if (desiredFormat==ma_format_unknown) {
Mf=ma_format_from_AudioStreamBasicDescription(pOrigFormat,&desiredFormat);
if (Mf !=Ms||desiredFormat==ma_format_unknown) {
desiredFormat=g_maFormatPriorities[0];
}
}
MA_ZERO_OBJECT(&bestDeviceFormatSoFar);
hasSupportedFormat=MA_FALSE;
for (iFormat=0; iFormat<deviceFormatDescriptionCount;++iFormat) {
ma_format formatFromDescription;
Me formatResult=ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat,&formatFromDescription);
if (formatResult==Ms&&formatFromDescription !=ma_format_unknown) {
hasSupportedFormat=MA_TRUE;
bestDeviceFormatSoFar=pDeviceFormatDescriptions[iFormat].mFormat;
break;
}
}
if (!hasSupportedFormat) {
ma_free(pDeviceFormatDescriptions,&Mc->allocationCallbacks);
Mr MA_FORMAT_NOT_SUPPORTED;
}
for (iFormat=0; iFormat<deviceFormatDescriptionCount;++iFormat) {
AudioStreamBasicDescription thisDeviceFormat=pDeviceFormatDescriptions[iFormat].mFormat;
ma_format thisSampleFormat;
Me formatResult;
ma_format bestSampleFormatSoFar;
formatResult=ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat,&thisSampleFormat);
if (formatResult !=Ms||thisSampleFormat==ma_format_unknown) {
continue;
}
ma_format_from_AudioStreamBasicDescription(&bestDeviceFormatSoFar,&bestSampleFormatSoFar);
if (thisDeviceFormat.mSampleRate !=desiredSampleRate) {
if (bestDeviceFormatSoFar.mSampleRate==desiredSampleRate) {
continue;
} else {
if (thisDeviceFormat.mChannelsPerFrame !=desiredChannelCount) {
 if (bestDeviceFormatSoFar.mChannelsPerFrame==desiredChannelCount) {
 continue;
 } else {
 if (ma_get_format_priority_index(thisSampleFormat)<ma_get_format_priority_index(bestSampleFormatSoFar)) {
 bestDeviceFormatSoFar=thisDeviceFormat;
 continue;
 } else {
 continue;
 }
 }
} else {
 if (bestDeviceFormatSoFar.mChannelsPerFrame==desiredChannelCount) {
 if (ma_get_format_priority_index(thisSampleFormat)<ma_get_format_priority_index(bestSampleFormatSoFar)) {
 bestDeviceFormatSoFar=thisDeviceFormat;
 continue;
 } else {
 continue;
 }
 } else {
 bestDeviceFormatSoFar=thisDeviceFormat;
 continue;
 }
}
}
} else {
if (bestDeviceFormatSoFar.mSampleRate !=desiredSampleRate) {
bestDeviceFormatSoFar=thisDeviceFormat;
continue;
} else {
if (thisDeviceFormat.mChannelsPerFrame==desiredChannelCount) {
 if (bestDeviceFormatSoFar.mChannelsPerFrame !=desiredChannelCount) {
 bestDeviceFormatSoFar=thisDeviceFormat;
 continue;
 } else {
 if (thisSampleFormat==desiredFormat) {
 bestDeviceFormatSoFar=thisDeviceFormat;
 break;
 } else {
 if (ma_get_format_priority_index(thisSampleFormat)<ma_get_format_priority_index(bestSampleFormatSoFar)) {
 bestDeviceFormatSoFar=thisDeviceFormat;
 continue;
 } else {
 continue;
 }
 }
 }
} else {
 if (bestDeviceFormatSoFar.mChannelsPerFrame==desiredChannelCount) {
 continue;
 } else {
 if (thisSampleFormat==bestSampleFormatSoFar) {
 if (ma_get_format_priority_index(thisSampleFormat)<ma_get_format_priority_index(bestSampleFormatSoFar)) {
 bestDeviceFormatSoFar=thisDeviceFormat;
 continue;
 } else {
 continue;
 }
 }
 }
}
}
}
}
*pFormat=bestDeviceFormatSoFar;
ma_free(pDeviceFormatDescriptions,&Mc->allocationCallbacks);
Mr Ms;
}
static Me ma_get_AudioUnit_channel_map(ma_context*Mc,AudioUnit audioUnit,ma_device_type deviceType,ma_channel*pChannelMap,size_t channelMapCap)
{
AudioUnitScope deviceScope;
AudioUnitElement deviceBus;
UInt32 channelLayoutSize;
OSStatus status;
AudioChannelLayout*pChannelLayout;
Me Mf;
MA_ASSERT(Mc !=NULL);
if (deviceType==Mt) {
deviceScope=kAudioUnitScope_Input;
deviceBus=MA_COREAUDIO_OUTPUT_BUS;
} else {
deviceScope=kAudioUnitScope_Output;
deviceBus=MA_COREAUDIO_INPUT_BUS;
}
status=((ma_AudioUnitGetPropertyInfo_proc)Mc->coreaudio.AudioUnitGetPropertyInfo)(audioUnit,kAudioUnitProperty_AudioChannelLayout,deviceScope,deviceBus,&channelLayoutSize,NULL);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
pChannelLayout=(AudioChannelLayout*)ma_malloc(channelLayoutSize,&Mc->allocationCallbacks);
if (pChannelLayout==NULL) {
Mr MA_OUT_OF_MEMORY;
}
status=((ma_AudioUnitGetProperty_proc)Mc->coreaudio.AudioUnitGetProperty)(audioUnit,kAudioUnitProperty_AudioChannelLayout,deviceScope,deviceBus,pChannelLayout,&channelLayoutSize);
if (status !=noErr) {
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr ma_result_from_OSStatus(status);
}
Mf=ma_get_channel_map_from_AudioChannelLayout(pChannelLayout,pChannelMap,channelMapCap);
if (Mf !=Ms) {
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr Mf;
}
ma_free(pChannelLayout,&Mc->allocationCallbacks);
Mr Ms;
}
#endif
#if !defined(MA_APPLE_DESKTOP)
static Mv ma_AVAudioSessionPortDescription_to_device_info(AVAudioSessionPortDescription*pPortDesc,ma_device_info*pInfo)
{
MA_ZERO_OBJECT(pInfo);
ma_strncpy_s(pInfo->name,sizeof(pInfo->name),[pPortDesc.portName UTF8String],(size_t)-1);
ma_strncpy_s(pInfo->id.coreaudio,sizeof(pInfo->id.coreaudio),[pPortDesc.UID UTF8String],(size_t)-1);
}
#endif
static Me ma_context_enumerate_devices__coreaudio(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
#if defined(MA_APPLE_DESKTOP)
UInt32 deviceCount;
AudioObjectID*pDeviceObjectIDs;
AudioObjectID defaultDeviceObjectIDPlayback;
AudioObjectID defaultDeviceObjectIDCapture;
Me Mf;
UInt32 iDevice;
ma_find_default_AudioObjectID(Mc,Mt,&defaultDeviceObjectIDPlayback);
ma_find_default_AudioObjectID(Mc,ma_device_type_capture,&defaultDeviceObjectIDCapture);
Mf=ma_get_device_object_ids__coreaudio(Mc,&deviceCount,&pDeviceObjectIDs);
if (Mf !=Ms) {
Mr Mf;
}
for (iDevice=0; iDevice<deviceCount;++iDevice) {
AudioObjectID deviceObjectID=pDeviceObjectIDs[iDevice];
ma_device_info info;
MA_ZERO_OBJECT(&info);
if (ma_get_AudioObject_uid(Mc,deviceObjectID,sizeof(info.id.coreaudio),info.id.coreaudio) !=Ms) {
continue;
}
if (ma_get_AudioObject_name(Mc,deviceObjectID,sizeof(info.name),info.name) !=Ms) {
continue;
}
if (ma_does_AudioObject_support_playback(Mc,deviceObjectID)) {
if (deviceObjectID==defaultDeviceObjectIDPlayback) {
info.isDefault=MA_TRUE;
}
if (!callback(Mc,Mt,&info,pUserData)) {
break;
}
}
if (ma_does_AudioObject_support_capture(Mc,deviceObjectID)) {
if (deviceObjectID==defaultDeviceObjectIDCapture) {
info.isDefault=MA_TRUE;
}
if (!callback(Mc,ma_device_type_capture,&info,pUserData)) {
break;
}
}
}
ma_free(pDeviceObjectIDs,&Mc->allocationCallbacks);
#else
ma_device_info info;
NSArray*pInputs=[[[AVAudioSession sharedInstance] currentRoute] inputs];
NSArray*pOutputs=[[[AVAudioSession sharedInstance] currentRoute] outputs];
for (AVAudioSessionPortDescription*pPortDesc in pOutputs) {
ma_AVAudioSessionPortDescription_to_device_info(pPortDesc,&info);
if (!callback(Mc,Mt,&info,pUserData)) {
Mr Ms;
}
}
for (AVAudioSessionPortDescription*pPortDesc in pInputs) {
ma_AVAudioSessionPortDescription_to_device_info(pPortDesc,&info);
if (!callback(Mc,ma_device_type_capture,&info,pUserData)) {
Mr Ms;
}
}
#endif
Mr Ms;
}
static Me ma_context_get_device_info__coreaudio(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
Me Mf;
MA_ASSERT(Mc !=NULL);
#if defined(MA_APPLE_DESKTOP)
{
AudioObjectID deviceObjectID;
AudioObjectID defaultDeviceObjectID;
UInt32 streamDescriptionCount;
AudioStreamRangedDescription*pStreamDescriptions;
UInt32 iStreamDescription;
UInt32 sampleRateRangeCount;
AudioValueRange*pSampleRateRanges;
ma_find_default_AudioObjectID(Mc,deviceType,&defaultDeviceObjectID);
Mf=ma_find_AudioObjectID(Mc,deviceType,pDeviceID,&deviceObjectID);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_get_AudioObject_uid(Mc,deviceObjectID,sizeof(pDeviceInfo->id.coreaudio),pDeviceInfo->id.coreaudio);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_get_AudioObject_name(Mc,deviceObjectID,sizeof(pDeviceInfo->name),pDeviceInfo->name);
if (Mf !=Ms) {
Mr Mf;
}
if (deviceObjectID==defaultDeviceObjectID) {
pDeviceInfo->isDefault=MA_TRUE;
}
pDeviceInfo->nativeDataFormatCount=0;
{
ma_format uniqueFormats[ma_format_count];
M3 uniqueFormatCount=0;
M3 Mh;
Mf=ma_get_AudioObject_channel_count(Mc,deviceObjectID,deviceType,&Mh);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_get_AudioObject_stream_descriptions(Mc,deviceObjectID,deviceType,&streamDescriptionCount,&pStreamDescriptions);
if (Mf !=Ms) {
Mr Mf;
}
for (iStreamDescription=0; iStreamDescription<streamDescriptionCount;++iStreamDescription) {
ma_format format;
ma_bool32 hasFormatBeenHandled=MA_FALSE;
M3 iOutputFormat;
M3 iSampleRate;
Mf=ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat,&format);
if (Mf !=Ms) {
 continue;
}
MA_ASSERT(format !=ma_format_unknown);
for (iOutputFormat=0; iOutputFormat<uniqueFormatCount;++iOutputFormat) {
 if (uniqueFormats[iOutputFormat]==format) {
 hasFormatBeenHandled=MA_TRUE;
 break;
 }
}
if (hasFormatBeenHandled) {
 continue;
}
uniqueFormats[uniqueFormatCount]=format;
uniqueFormatCount+=1;
Mf=ma_get_AudioObject_sample_rates(Mc,deviceObjectID,deviceType,&sampleRateRangeCount,&pSampleRateRanges);
if (Mf !=Ms) {
 Mr Mf;
}
for (iSampleRate=0; iSampleRate<sampleRateRangeCount;++iSampleRate) {
 M3 iStandardSampleRate;
 for (iStandardSampleRate=0; iStandardSampleRate<ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate+=1) {
 M3 standardSampleRate=g_maStandardSampleRatePriorities[iStandardSampleRate];
 if (standardSampleRate>=pSampleRateRanges[iSampleRate].mMinimum&&standardSampleRate<=pSampleRateRanges[iSampleRate].mMaximum) {
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=format;
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=Mh;
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=standardSampleRate;
 pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=0;
 pDeviceInfo->nativeDataFormatCount+=1;
 if (pDeviceInfo->nativeDataFormatCount>=ma_countof(pDeviceInfo->nativeDataFormats)) {
 break;
 }
 }
 }
}
ma_free(pSampleRateRanges,&Mc->allocationCallbacks);
if (pDeviceInfo->nativeDataFormatCount>=ma_countof(pDeviceInfo->nativeDataFormats)) {
 break;
}
}
ma_free(pStreamDescriptions,&Mc->allocationCallbacks);
}
}
#else
{
AudioComponentDescription desc;
AudioComponent component;
AudioUnit audioUnit;
OSStatus status;
AudioUnitScope formatScope;
AudioUnitElement formatElement;
AudioStreamBasicDescription bestFormat;
UInt32 propSize;
if (pDeviceID !=NULL&&pDeviceID->coreaudio[0] !='\0') {
ma_bool32 found=MA_FALSE;
if (deviceType==Mt) {
NSArray*pOutputs=[[[AVAudioSession sharedInstance] currentRoute] outputs];
for (AVAudioSessionPortDescription*pPortDesc in pOutputs) {
 if (strcmp(pDeviceID->coreaudio,[pPortDesc.UID UTF8String])==0) {
 ma_AVAudioSessionPortDescription_to_device_info(pPortDesc,pDeviceInfo);
 found=MA_TRUE;
 break;
 }
}
} else {
NSArray*pInputs=[[[AVAudioSession sharedInstance] currentRoute] inputs];
for (AVAudioSessionPortDescription*pPortDesc in pInputs) {
 if (strcmp(pDeviceID->coreaudio,[pPortDesc.UID UTF8String])==0) {
 ma_AVAudioSessionPortDescription_to_device_info(pPortDesc,pDeviceInfo);
 found=MA_TRUE;
 break;
 }
}
}
if (!found) {
Mr MA_DOES_NOT_EXIST;
}
} else {
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
}
desc.componentType=kAudioUnitType_Output;
desc.componentSubType=kAudioUnitSubType_RemoteIO;
desc.componentManufacturer=kAudioUnitManufacturer_Apple;
desc.componentFlags=0;
desc.componentFlagsMask=0;
component=((ma_AudioComponentFindNext_proc)Mc->coreaudio.AudioComponentFindNext)(NULL,&desc);
if (component==NULL) {
Mr MA_FAILED_TO_INIT_BACKEND;
}
status=((ma_AudioComponentInstanceNew_proc)Mc->coreaudio.AudioComponentInstanceNew)(component,&audioUnit);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
formatScope=(deviceType==Mt)?kAudioUnitScope_Input:kAudioUnitScope_Output;
formatElement=(deviceType==Mt)?MA_COREAUDIO_OUTPUT_BUS:MA_COREAUDIO_INPUT_BUS;
propSize=sizeof(bestFormat);
status=((ma_AudioUnitGetProperty_proc)Mc->coreaudio.AudioUnitGetProperty)(audioUnit,kAudioUnitProperty_StreamFormat,formatScope,formatElement,&bestFormat,&propSize);
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(audioUnit);
Mr ma_result_from_OSStatus(status);
}
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(audioUnit);
audioUnit=NULL;
pDeviceInfo->nativeDataFormatCount=1;
Mf=ma_format_from_AudioStreamBasicDescription(&bestFormat,&pDeviceInfo->nativeDataFormats[0].format);
if (Mf !=Ms) {
Mr Mf;
}
pDeviceInfo->nativeDataFormats[0].Mh=bestFormat.mChannelsPerFrame;
@autoreleasepool {
AVAudioSession*pAudioSession=[AVAudioSession sharedInstance];
MA_ASSERT(pAudioSession !=NULL);
pDeviceInfo->nativeDataFormats[0].sampleRate=(M3)pAudioSession.sampleRate;
}
}
#endif
(Mv)pDeviceInfo;
Mr Ms;
}
static AudioBufferList*ma_allocate_AudioBufferList__coreaudio(M3 sizeInFrames,ma_format format,M3 Mh,ma_stream_layout layout,const ma_allocation_callbacks*pAllocationCallbacks)
{
AudioBufferList*pBufferList;
UInt32 audioBufferSizeInBytes;
size_t allocationSize;
MA_ASSERT(sizeInFrames>0);
MA_ASSERT(format !=ma_format_unknown);
MA_ASSERT(Mh>0);
allocationSize=sizeof(AudioBufferList)-sizeof(AudioBuffer);
if (layout==ma_stream_layout_interleaved) {
allocationSize+=sizeof(AudioBuffer)*1;
} else {
allocationSize+=sizeof(AudioBuffer)*Mh;
}
allocationSize+=sizeInFrames*ma_get_bytes_per_frame(format,Mh);
pBufferList=(AudioBufferList*)ma_malloc(allocationSize,pAllocationCallbacks);
if (pBufferList==NULL) {
Mr NULL;
}
audioBufferSizeInBytes=(UInt32)(sizeInFrames*ma_get_bytes_per_sample(format));
if (layout==ma_stream_layout_interleaved) {
pBufferList->mNumberBuffers=1;
pBufferList->mBuffers[0].mNumberChannels=Mh;
pBufferList->mBuffers[0].mDataByteSize=audioBufferSizeInBytes*Mh;
pBufferList->mBuffers[0].mData=(ma_uint8*)pBufferList+sizeof(AudioBufferList);
} else {
M3 iBuffer;
pBufferList->mNumberBuffers=Mh;
for (iBuffer=0; iBuffer<pBufferList->mNumberBuffers;++iBuffer) {
pBufferList->mBuffers[iBuffer].mNumberChannels=1;
pBufferList->mBuffers[iBuffer].mDataByteSize=audioBufferSizeInBytes;
pBufferList->mBuffers[iBuffer].mData=(ma_uint8*)pBufferList+((sizeof(AudioBufferList)-sizeof(AudioBuffer))+(sizeof(AudioBuffer)*Mh))+(audioBufferSizeInBytes*iBuffer);
}
}
Mr pBufferList;
}
static Me ma_device_realloc_AudioBufferList__coreaudio(ma_device*Md,M3 sizeInFrames,ma_format format,M3 Mh,ma_stream_layout layout)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(format !=ma_format_unknown);
MA_ASSERT(Mh>0);
if (Md->coreaudio.audioBufferCapInFrames<sizeInFrames) {
AudioBufferList*pNewAudioBufferList;
pNewAudioBufferList=ma_allocate_AudioBufferList__coreaudio(sizeInFrames,format,Mh,layout,&Md->Mc->allocationCallbacks);
if (pNewAudioBufferList==NULL) {
Mr MA_OUT_OF_MEMORY;
}
ma_free(Md->coreaudio.pAudioBufferList,&Md->Mc->allocationCallbacks);
Md->coreaudio.pAudioBufferList=pNewAudioBufferList;
Md->coreaudio.audioBufferCapInFrames=sizeInFrames;
}
Mr Ms;
}
static OSStatus ma_on_output__coreaudio(Mv*pUserData,AudioUnitRenderActionFlags*pActionFlags,const AudioTimeStamp*pTimeStamp,UInt32 busNumber,UInt32 frameCount,AudioBufferList*pBufferList)
{
ma_device*Md=(ma_device*)pUserData;
ma_stream_layout layout;
MA_ASSERT(Md !=NULL);
layout=ma_stream_layout_interleaved;
if (pBufferList->mBuffers[0].mNumberChannels !=Md->playback.internalChannels) {
layout=ma_stream_layout_deinterleaved;
}
if (layout==ma_stream_layout_interleaved) {
UInt32 iBuffer;
for (iBuffer=0; iBuffer<pBufferList->mNumberBuffers;++iBuffer) {
if (pBufferList->mBuffers[iBuffer].mNumberChannels==Md->playback.internalChannels) {
M3 frameCountForThisBuffer=pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
if (frameCountForThisBuffer>0) {
 ma_device_handle_backend_data_callback(Md,pBufferList->mBuffers[iBuffer].mData,NULL,frameCountForThisBuffer);
}
} else {
MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData,pBufferList->mBuffers[iBuffer].mDataByteSize);
}
}
} else {
MA_ASSERT(Md->playback.internalChannels<=MA_MAX_CHANNELS);
if ((pBufferList->mNumberBuffers % Md->playback.internalChannels)==0) {
ma_uint8 tempBuffer[4096];
UInt32 iBuffer;
for (iBuffer=0; iBuffer<pBufferList->mNumberBuffers; iBuffer+=Md->playback.internalChannels) {
M3 frameCountPerBuffer=pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_sample(Md->playback.internalFormat);
M3 framesRemaining=frameCountPerBuffer;
while (framesRemaining>0) {
 Mv*ppDeinterleavedBuffers[MA_MAX_CHANNELS];
 M3 iChannel;
 M3 framesToRead=sizeof(tempBuffer) / ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
 if (framesToRead>framesRemaining) {
 framesToRead=framesRemaining;
 }
 ma_device_handle_backend_data_callback(Md,tempBuffer,NULL,framesToRead);
 for (iChannel=0; iChannel<Md->playback.internalChannels;++iChannel) {
 ppDeinterleavedBuffers[iChannel]=(Mv*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData,(frameCountPerBuffer-framesRemaining)*ma_get_bytes_per_sample(Md->playback.internalFormat));
 }
 ma_deinterleave_pcm_frames(Md->playback.internalFormat,Md->playback.internalChannels,framesToRead,tempBuffer,ppDeinterleavedBuffers);
 framesRemaining-=framesToRead;
}
}
}
}
(Mv)pActionFlags;
(Mv)pTimeStamp;
(Mv)busNumber;
(Mv)frameCount;
Mr noErr;
}
static OSStatus ma_on_input__coreaudio(Mv*pUserData,AudioUnitRenderActionFlags*pActionFlags,const AudioTimeStamp*pTimeStamp,UInt32 busNumber,UInt32 frameCount,AudioBufferList*pUnusedBufferList)
{
ma_device*Md=(ma_device*)pUserData;
AudioBufferList*pRenderedBufferList;
Me Mf;
ma_stream_layout layout;
M3 iBuffer;
OSStatus status;
MA_ASSERT(Md !=NULL);
pRenderedBufferList=(AudioBufferList*)Md->coreaudio.pAudioBufferList;
MA_ASSERT(pRenderedBufferList);
layout=ma_stream_layout_interleaved;
if (pRenderedBufferList->mBuffers[0].mNumberChannels !=Md->capture.internalChannels) {
layout=ma_stream_layout_deinterleaved;
}
Mf=ma_device_realloc_AudioBufferList__coreaudio(Md,frameCount,Md->capture.internalFormat,Md->capture.internalChannels,layout);
if (Mf !=Ms) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.\n");
Mr noErr;
}
pRenderedBufferList=(AudioBufferList*)Md->coreaudio.pAudioBufferList;
MA_ASSERT(pRenderedBufferList);
for (iBuffer=0; iBuffer<pRenderedBufferList->mNumberBuffers;++iBuffer) {
pRenderedBufferList->mBuffers[iBuffer].mDataByteSize=Md->coreaudio.audioBufferCapInFrames*ma_get_bytes_per_sample(Md->capture.internalFormat)*pRenderedBufferList->mBuffers[iBuffer].mNumberChannels;
}
status=((ma_AudioUnitRender_proc)Md->Mc->coreaudio.AudioUnitRender)((AudioUnit)Md->coreaudio.audioUnitCapture,pActionFlags,pTimeStamp,busNumber,frameCount,pRenderedBufferList);
if (status !=noErr) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_DEBUG, "ERROR: AudioUnitRender() failed with %d.\n", (int)status);
Mr status;
}
if (layout==ma_stream_layout_interleaved) {
for (iBuffer=0; iBuffer<pRenderedBufferList->mNumberBuffers;++iBuffer) {
if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels==Md->capture.internalChannels) {
ma_device_handle_backend_data_callback(Md,NULL,pRenderedBufferList->mBuffers[iBuffer].mData,frameCount);
} else {
ma_uint8 silentBuffer[4096];
M3 framesRemaining;
MA_ZERO_MEMORY(silentBuffer,sizeof(silentBuffer));
framesRemaining=frameCount;
while (framesRemaining>0) {
 M3 framesToSend=sizeof(silentBuffer) / ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
 if (framesToSend>framesRemaining) {
 framesToSend=framesRemaining;
 }
 ma_device_handle_backend_data_callback(Md,NULL,silentBuffer,framesToSend);
 framesRemaining-=framesToSend;
}
}
}
} else {
MA_ASSERT(Md->capture.internalChannels<=MA_MAX_CHANNELS);
if ((pRenderedBufferList->mNumberBuffers % Md->capture.internalChannels)==0) {
ma_uint8 tempBuffer[4096];
for (iBuffer=0; iBuffer<pRenderedBufferList->mNumberBuffers; iBuffer+=Md->capture.internalChannels) {
M3 framesRemaining=frameCount;
while (framesRemaining>0) {
 Mv*ppDeinterleavedBuffers[MA_MAX_CHANNELS];
 M3 iChannel;
 M3 framesToSend=sizeof(tempBuffer) / ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
 if (framesToSend>framesRemaining) {
 framesToSend=framesRemaining;
 }
 for (iChannel=0; iChannel<Md->capture.internalChannels;++iChannel) {
 ppDeinterleavedBuffers[iChannel]=(Mv*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer+iChannel].mData,(frameCount-framesRemaining)*ma_get_bytes_per_sample(Md->capture.internalFormat));
 }
 ma_interleave_pcm_frames(Md->capture.internalFormat,Md->capture.internalChannels,framesToSend,(const Mv**)ppDeinterleavedBuffers,tempBuffer);
 ma_device_handle_backend_data_callback(Md,NULL,tempBuffer,framesToSend);
 framesRemaining-=framesToSend;
}
}
}
}
(Mv)pActionFlags;
(Mv)pTimeStamp;
(Mv)busNumber;
(Mv)frameCount;
(Mv)pUnusedBufferList;
Mr noErr;
}
static Mv on_start_stop__coreaudio(Mv*pUserData,AudioUnit audioUnit,AudioUnitPropertyID propertyID,AudioUnitScope scope,AudioUnitElement element)
{
ma_device*Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
if (((audioUnit==Md->coreaudio.audioUnitPlayback)&&Md->coreaudio.isSwitchingPlaybackDevice)||
((audioUnit==Md->coreaudio.audioUnitCapture)&&Md->coreaudio.isSwitchingCaptureDevice)) {
Mr;
}
if (ma_device_get_state(Md)==ma_device_state_uninitialized||ma_device_get_state(Md)==ma_device_state_stopping||ma_device_get_state(Md)==ma_device_state_stopped) {
ma_device__on_notification_stopped(Md);
} else {
UInt32 isRunning;
UInt32 isRunningSize=sizeof(isRunning);
OSStatus status=((ma_AudioUnitGetProperty_proc)Md->Mc->coreaudio.AudioUnitGetProperty)(audioUnit,kAudioOutputUnitProperty_IsRunning,scope,element,&isRunning,&isRunningSize);
if (status !=noErr) {
goto done;
}
if (!isRunning) {
if (((audioUnit==Md->coreaudio.audioUnitPlayback)&&Md->coreaudio.isDefaultPlaybackDevice)||
((audioUnit==Md->coreaudio.audioUnitCapture)&&Md->coreaudio.isDefaultCaptureDevice)) {
if (((audioUnit==Md->coreaudio.audioUnitPlayback)&&Md->coreaudio.isSwitchingPlaybackDevice)||
 ((audioUnit==Md->coreaudio.audioUnitCapture)&&Md->coreaudio.isSwitchingCaptureDevice)) {
 goto done;
}
goto done;
}
ma_device__on_notification_stopped(Md);
}
}
(Mv)propertyID;
done:
ma_event_signal(&Md->coreaudio.stopEvent);
}
#if defined(MA_APPLE_DESKTOP)
static ma_spinlock g_DeviceTrackingInitLock_CoreAudio=0;
static M3 g_DeviceTrackingInitCounter_CoreAudio=0;
static ma_mutex g_DeviceTrackingMutex_CoreAudio;
static ma_device**g_ppTrackedDevices_CoreAudio=NULL;
static M3 g_TrackedDeviceCap_CoreAudio=0;
static M3 g_TrackedDeviceCount_CoreAudio=0;
static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID,UInt32 addressCount,const AudioObjectPropertyAddress*pAddresses,Mv*pUserData)
{
ma_device_type deviceType;
if (addressCount==0) {
Mr noErr;
}
if (pAddresses[0].mSelector==kAudioHardwarePropertyDefaultOutputDevice) {
deviceType=Mt;
} else if (pAddresses[0].mSelector==kAudioHardwarePropertyDefaultInputDevice) {
deviceType=ma_device_type_capture;
} else {
Mr noErr;
}
ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
{
M3 iDevice;
for (iDevice=0; iDevice<g_TrackedDeviceCount_CoreAudio; iDevice+=1) {
Me reinitResult;
ma_device*Md;
Md=g_ppTrackedDevices_CoreAudio[iDevice];
if (Md->type==deviceType||Md->type==ma_device_type_duplex) {
if (deviceType==Mt) {
 Md->coreaudio.isSwitchingPlaybackDevice=MA_TRUE;
 reinitResult=ma_device_reinit_internal__coreaudio(Md,deviceType,MA_TRUE);
 Md->coreaudio.isSwitchingPlaybackDevice=MA_FALSE;
} else {
 Md->coreaudio.isSwitchingCaptureDevice=MA_TRUE;
 reinitResult=ma_device_reinit_internal__coreaudio(Md,deviceType,MA_TRUE);
 Md->coreaudio.isSwitchingCaptureDevice=MA_FALSE;
}
if (reinitResult==Ms) {
 ma_device__post_init_setup(Md,deviceType);
 if (ma_device_get_state(Md)==ma_device_state_started) {
 OSStatus status;
 if (deviceType==Mt) {
 status=((ma_AudioOutputUnitStart_proc)Md->Mc->coreaudio.AudioOutputUnitStart)((AudioUnit)Md->coreaudio.audioUnitPlayback);
 if (status !=noErr) {
 if (Md->type==ma_device_type_duplex) {
 ((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitCapture);
 }
 ma_device__set_state(Md,ma_device_state_stopped);
 }
 } else if (deviceType==ma_device_type_capture) {
 status=((ma_AudioOutputUnitStart_proc)Md->Mc->coreaudio.AudioOutputUnitStart)((AudioUnit)Md->coreaudio.audioUnitCapture);
 if (status !=noErr) {
 if (Md->type==ma_device_type_duplex) {
 ((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitPlayback);
 }
 ma_device__set_state(Md,ma_device_state_stopped);
 }
 }
 }
 ma_device__on_notification_rerouted(Md);
}
}
}
}
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
(Mv)objectID;
(Mv)pUserData;
Mr noErr;
}
static Me ma_context__init_device_tracking__coreaudio(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
{
if (g_DeviceTrackingInitCounter_CoreAudio==0) {
AudioObjectPropertyAddress propAddress;
propAddress.mScope=kAudioObjectPropertyScopeGlobal;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
ma_mutex_init(&g_DeviceTrackingMutex_CoreAudio);
propAddress.mSelector=kAudioHardwarePropertyDefaultInputDevice;
((ma_AudioObjectAddPropertyListener_proc)Mc->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject,&propAddress,&ma_default_device_changed__coreaudio,NULL);
propAddress.mSelector=kAudioHardwarePropertyDefaultOutputDevice;
((ma_AudioObjectAddPropertyListener_proc)Mc->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject,&propAddress,&ma_default_device_changed__coreaudio,NULL);
}
g_DeviceTrackingInitCounter_CoreAudio+=1;
}
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
Mr Ms;
}
static Me ma_context__uninit_device_tracking__coreaudio(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
{
if (g_DeviceTrackingInitCounter_CoreAudio>0)
g_DeviceTrackingInitCounter_CoreAudio-=1;
if (g_DeviceTrackingInitCounter_CoreAudio==0) {
AudioObjectPropertyAddress propAddress;
propAddress.mScope=kAudioObjectPropertyScopeGlobal;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
propAddress.mSelector=kAudioHardwarePropertyDefaultInputDevice;
((ma_AudioObjectRemovePropertyListener_proc)Mc->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject,&propAddress,&ma_default_device_changed__coreaudio,NULL);
propAddress.mSelector=kAudioHardwarePropertyDefaultOutputDevice;
((ma_AudioObjectRemovePropertyListener_proc)Mc->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject,&propAddress,&ma_default_device_changed__coreaudio,NULL);
if (g_ppTrackedDevices_CoreAudio !=NULL) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.");
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
Mr MA_INVALID_OPERATION;
}
ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio);
}
}
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
Mr Ms;
}
static Me ma_device__track__coreaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
{
if (g_TrackedDeviceCap_CoreAudio<=g_TrackedDeviceCount_CoreAudio) {
M3 newCap;
ma_device**ppNewDevices;
newCap=g_TrackedDeviceCap_CoreAudio*2;
if (newCap==0) {
newCap=1;
}
ppNewDevices=(ma_device**)ma_realloc(g_ppTrackedDevices_CoreAudio,sizeof(*g_ppTrackedDevices_CoreAudio)*newCap,&Md->Mc->allocationCallbacks);
if (ppNewDevices==NULL) {
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
Mr MA_OUT_OF_MEMORY;
}
g_ppTrackedDevices_CoreAudio=ppNewDevices;
g_TrackedDeviceCap_CoreAudio=newCap;
}
g_ppTrackedDevices_CoreAudio[g_TrackedDeviceCount_CoreAudio]=Md;
g_TrackedDeviceCount_CoreAudio+=1;
}
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
Mr Ms;
}
static Me ma_device__untrack__coreaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
{
M3 iDevice;
for (iDevice=0; iDevice<g_TrackedDeviceCount_CoreAudio; iDevice+=1) {
if (g_ppTrackedDevices_CoreAudio[iDevice]==Md) {
M3 jDevice;
for (jDevice=iDevice; jDevice<g_TrackedDeviceCount_CoreAudio-1; jDevice+=1) {
 g_ppTrackedDevices_CoreAudio[jDevice]=g_ppTrackedDevices_CoreAudio[jDevice+1];
}
g_TrackedDeviceCount_CoreAudio-=1;
if (g_TrackedDeviceCount_CoreAudio==0) {
 ma_free(g_ppTrackedDevices_CoreAudio,&Md->Mc->allocationCallbacks);
 g_ppTrackedDevices_CoreAudio=NULL;
 g_TrackedDeviceCap_CoreAudio=0;
}
break;
}
}
}
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
Mr Ms;
}
#endif
#if defined(MA_APPLE_MOBILE)
@interface ma_ios_notification_handler:NSObject {
ma_device*m_pDevice;
}
@end
@implementation ma_ios_notification_handler
-(id)init:(ma_device*)Md
{
self=[super init];
m_pDevice=Md;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
Mr self;
}
-(Mv)dealloc
{
[self remove_handler];
#if defined(__has_feature)
#if !__has_feature(objc_arc)
[super dealloc];
#endif
#endif
}
-(Mv)remove_handler
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
}
-(Mv)handle_interruption:(NSNotification*)pNotification
{
NSInteger type=[[[pNotification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
switch (type)
{
case AVAudioSessionInterruptionTypeBegan:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeBegan\n");
ma_device_stop(m_pDevice);
ma_device__on_notification_interruption_began(m_pDevice);
} break;
case AVAudioSessionInterruptionTypeEnded:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n");
ma_device__on_notification_interruption_ended(m_pDevice);
} break;
}
}
-(Mv)handle_route_change:(NSNotification*)pNotification
{
AVAudioSession*pSession=[AVAudioSession sharedInstance];
NSInteger reason=[[[pNotification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
switch (reason)
{
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n");
} break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n");
} break;
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n");
} break;
case AVAudioSessionRouteChangeReasonWakeFromSleep:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n");
} break;
case AVAudioSessionRouteChangeReasonOverride:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n");
} break;
case AVAudioSessionRouteChangeReasonCategoryChange:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n");
} break;
case AVAudioSessionRouteChangeReasonUnknown:
default:
{
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n");
} break;
}
ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels);
ma_device__on_notification_rerouted(m_pDevice);
}
@end
#endif
static Me ma_device_uninit__coreaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(ma_device_get_state(Md)==ma_device_state_uninitialized);
#if defined(MA_APPLE_DESKTOP)
ma_device__untrack__coreaudio(Md);
#endif
#if defined(MA_APPLE_MOBILE)
if (Md->coreaudio.pNotificationHandler !=NULL) {
ma_ios_notification_handler*pNotificationHandler=(MA_BRIDGE_TRANSFER ma_ios_notification_handler*)Md->coreaudio.pNotificationHandler;
[pNotificationHandler remove_handler];
}
#endif
if (Md->coreaudio.audioUnitCapture !=NULL) {
((ma_AudioComponentInstanceDispose_proc)Md->Mc->coreaudio.AudioComponentInstanceDispose)((AudioUnit)Md->coreaudio.audioUnitCapture);
}
if (Md->coreaudio.audioUnitPlayback !=NULL) {
((ma_AudioComponentInstanceDispose_proc)Md->Mc->coreaudio.AudioComponentInstanceDispose)((AudioUnit)Md->coreaudio.audioUnitPlayback);
}
if (Md->coreaudio.pAudioBufferList) {
ma_free(Md->coreaudio.pAudioBufferList,&Md->Mc->allocationCallbacks);
}
Mr Ms;
}
typedef struct
{
ma_bool32 allowNominalSampleRateChange;
ma_format formatIn;
M3 channelsIn;
M3 sampleRateIn;
ma_channel channelMapIn[MA_MAX_CHANNELS];
M3 periodSizeInFramesIn;
M3 periodSizeInMillisecondsIn;
M3 periodsIn;
ma_share_mode shareMode;
ma_performance_profile performanceProfile;
ma_bool32 registerStopEvent;
#if defined(MA_APPLE_DESKTOP)
AudioObjectID deviceObjectID;
#endif
AudioComponent component;
AudioUnit audioUnit;
AudioBufferList*pAudioBufferList;
ma_format formatOut;
M3 channelsOut;
M3 sampleRateOut;
ma_channel channelMapOut[MA_MAX_CHANNELS];
M3 periodSizeInFramesOut;
M3 periodsOut;
char deviceName[256];
} ma_device_init_internal_data__coreaudio;
static Me ma_device_init_internal__coreaudio(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_init_internal_data__coreaudio*pData,Mv*pDevice_DoNotReference)
{
Me Mf=Ms;
OSStatus status;
UInt32 enableIOFlag;
AudioStreamBasicDescription bestFormat;
M3 actualPeriodSizeInFrames;
AURenderCallbackStruct callbackInfo;
#if defined(MA_APPLE_DESKTOP)
AudioObjectID deviceObjectID;
#endif
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(Mc !=NULL);
MA_ASSERT(deviceType==Mt||deviceType==ma_device_type_capture);
#if defined(MA_APPLE_DESKTOP)
pData->deviceObjectID=0;
#endif
pData->component=NULL;
pData->audioUnit=NULL;
pData->pAudioBufferList=NULL;
#if defined(MA_APPLE_DESKTOP)
Mf=ma_find_AudioObjectID(Mc,deviceType,pDeviceID,&deviceObjectID);
if (Mf !=Ms) {
Mr Mf;
}
pData->deviceObjectID=deviceObjectID;
#endif
pData->periodsOut=pData->periodsIn;
if (pData->periodsOut==0) {
pData->periodsOut=MA_DEFAULT_PERIODS;
}
if (pData->periodsOut>16) {
pData->periodsOut=16;
}
status=((ma_AudioComponentInstanceNew_proc)Mc->coreaudio.AudioComponentInstanceNew)((AudioComponent)Mc->coreaudio.component,(AudioUnit*)&pData->audioUnit);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
enableIOFlag=1;
if (deviceType==ma_device_type_capture) {
enableIOFlag=0;
}
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output,MA_COREAUDIO_OUTPUT_BUS,&enableIOFlag,sizeof(enableIOFlag));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
enableIOFlag=(enableIOFlag==0)?1:0;
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Input,MA_COREAUDIO_INPUT_BUS,&enableIOFlag,sizeof(enableIOFlag));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
#if defined(MA_APPLE_DESKTOP)
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioOutputUnitProperty_CurrentDevice,kAudioUnitScope_Global,0,&deviceObjectID,sizeof(deviceObjectID));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(Mf);
}
#else
if (pDeviceID !=NULL) {
if (deviceType==ma_device_type_capture) {
ma_bool32 found=MA_FALSE;
NSArray*pInputs=[[[AVAudioSession sharedInstance] currentRoute] inputs];
for (AVAudioSessionPortDescription*pPortDesc in pInputs) {
if (strcmp(pDeviceID->coreaudio,[pPortDesc.UID UTF8String])==0) {
 [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
 found=MA_TRUE;
 break;
}
}
if (found==MA_FALSE) {
Mr MA_DOES_NOT_EXIST;
}
}
}
#endif
{
AudioStreamBasicDescription origFormat;
UInt32 origFormatSize=sizeof(origFormat);
AudioUnitScope formatScope=(deviceType==Mt)?kAudioUnitScope_Input:kAudioUnitScope_Output;
AudioUnitElement formatElement=(deviceType==Mt)?MA_COREAUDIO_OUTPUT_BUS:MA_COREAUDIO_INPUT_BUS;
if (deviceType==Mt) {
status=((ma_AudioUnitGetProperty_proc)Mc->coreaudio.AudioUnitGetProperty)(pData->audioUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,MA_COREAUDIO_OUTPUT_BUS,&origFormat,&origFormatSize);
} else {
status=((ma_AudioUnitGetProperty_proc)Mc->coreaudio.AudioUnitGetProperty)(pData->audioUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,MA_COREAUDIO_INPUT_BUS,&origFormat,&origFormatSize);
}
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
#if defined(MA_APPLE_DESKTOP)
Mf=ma_find_best_format__coreaudio(Mc,deviceObjectID,deviceType,pData->formatIn,pData->channelsIn,pData->sampleRateIn,&origFormat,&bestFormat);
if (Mf !=Ms) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr Mf;
}
if (pData->allowNominalSampleRateChange) {
AudioValueRange sampleRateRange;
AudioObjectPropertyAddress propAddress;
sampleRateRange.mMinimum=bestFormat.mSampleRate;
sampleRateRange.mMaximum=bestFormat.mSampleRate;
propAddress.mSelector=kAudioDevicePropertyNominalSampleRate;
propAddress.mScope=(deviceType==Mt)?kAudioObjectPropertyScopeOutput:kAudioObjectPropertyScopeInput;
propAddress.mElement=AUDIO_OBJECT_PROPERTY_ELEMENT;
status=((ma_AudioObjectSetPropertyData_proc)Mc->coreaudio.AudioObjectSetPropertyData)(deviceObjectID,&propAddress,0,NULL,sizeof(sampleRateRange),&sampleRateRange);
if (status !=noErr) {
bestFormat.mSampleRate=origFormat.mSampleRate;
}
} else {
bestFormat.mSampleRate=origFormat.mSampleRate;
}
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioUnitProperty_StreamFormat,formatScope,formatElement,&bestFormat,sizeof(bestFormat));
if (status !=noErr) {
bestFormat=origFormat;
}
#else
bestFormat=origFormat;
@autoreleasepool {
AVAudioSession*pAudioSession=[AVAudioSession sharedInstance];
MA_ASSERT(pAudioSession !=NULL);
[pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
bestFormat.mSampleRate=pAudioSession.sampleRate;
if (deviceType==Mt) {
bestFormat.mChannelsPerFrame=(UInt32)pAudioSession.outputNumberOfChannels;
}
#if 0
if (deviceType==ma_device_type_capture) {
bestFormat.mChannelsPerFrame=(UInt32)pAudioSession.inputNumberOfChannels;
}
#endif
}

status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioUnitProperty_StreamFormat,formatScope,formatElement,&bestFormat,sizeof(bestFormat));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
#endif
Mf=ma_format_from_AudioStreamBasicDescription(&bestFormat,&pData->formatOut);
if (Mf !=Ms) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr Mf;
}
if (pData->formatOut==ma_format_unknown) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr MA_FORMAT_NOT_SUPPORTED;
}
pData->channelsOut=bestFormat.mChannelsPerFrame;
pData->sampleRateOut=(M3)bestFormat.mSampleRate;
}
if (pData->channelsOut>MA_MAX_CHANNELS) {
pData->channelsOut=MA_MAX_CHANNELS;
}
#if defined(MA_APPLE_DESKTOP)
Mf=ma_get_AudioUnit_channel_map(Mc,pData->audioUnit,deviceType,pData->channelMapOut,pData->channelsOut);
if (Mf !=Ms) {
#if 0
Mf=ma_get_AudioObject_channel_map(Mc,deviceObjectID,deviceType,pData->channelMapOut,pData->channelsOut);
if (Mf !=Ms) {
Mr Mf;
}
#else
ma_channel_map_init_standard(ma_standard_channel_map_default,pData->channelMapOut,ma_countof(pData->channelMapOut),pData->channelsOut);
#endif
}
#else
ma_channel_map_init_standard(ma_standard_channel_map_default,pData->channelMapOut,ma_countof(pData->channelMapOut),pData->channelsOut);
#endif
if (pData->periodSizeInFramesIn==0) {
if (pData->periodSizeInMillisecondsIn==0) {
if (pData->performanceProfile==ma_performance_profile_low_latency) {
actualPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY,pData->sampleRateOut);
} else {
actualPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE,pData->sampleRateOut);
}
} else {
actualPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn,pData->sampleRateOut);
}
} else {
actualPeriodSizeInFrames=pData->periodSizeInFramesIn;
}
#if defined(MA_APPLE_DESKTOP)
Mf=ma_set_AudioObject_buffer_size_in_frames(Mc,deviceObjectID,deviceType,&actualPeriodSizeInFrames);
if (Mf !=Ms) {
Mr Mf;
}
#else
@autoreleasepool {
AVAudioSession*pAudioSession=[AVAudioSession sharedInstance];
MA_ASSERT(pAudioSession !=NULL);
[pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil];
actualPeriodSizeInFrames=ma_next_power_of_2((M3)(pAudioSession.IOBufferDuration*pAudioSession.sampleRate));
}
#endif
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioUnitProperty_MaximumFramesPerSlice,kAudioUnitScope_Global,0,&actualPeriodSizeInFrames,sizeof(actualPeriodSizeInFrames));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
pData->periodSizeInFramesOut=(M3)actualPeriodSizeInFrames;
if (deviceType==ma_device_type_capture) {
ma_bool32 isInterleaved=(bestFormat.mFormatFlags&kAudioFormatFlagIsNonInterleaved)==0;
AudioBufferList*pBufferList;
pBufferList=ma_allocate_AudioBufferList__coreaudio(pData->periodSizeInFramesOut,pData->formatOut,pData->channelsOut,(isInterleaved)?ma_stream_layout_interleaved:ma_stream_layout_deinterleaved,&Mc->allocationCallbacks);
if (pBufferList==NULL) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr MA_OUT_OF_MEMORY;
}
pData->pAudioBufferList=pBufferList;
}
callbackInfo.inputProcRefCon=pDevice_DoNotReference;
if (deviceType==Mt) {
callbackInfo.inputProc=ma_on_output__coreaudio;
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Global,0,&callbackInfo,sizeof(callbackInfo));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
} else {
callbackInfo.inputProc=ma_on_input__coreaudio;
status=((ma_AudioUnitSetProperty_proc)Mc->coreaudio.AudioUnitSetProperty)(pData->audioUnit,kAudioOutputUnitProperty_SetInputCallback,kAudioUnitScope_Global,0,&callbackInfo,sizeof(callbackInfo));
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
}
if (pData->registerStopEvent) {
status=((ma_AudioUnitAddPropertyListener_proc)Mc->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit,kAudioOutputUnitProperty_IsRunning,on_start_stop__coreaudio,pDevice_DoNotReference);
if (status !=noErr) {
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
}
status=((ma_AudioUnitInitialize_proc)Mc->coreaudio.AudioUnitInitialize)(pData->audioUnit);
if (status !=noErr) {
ma_free(pData->pAudioBufferList,&Mc->allocationCallbacks);
pData->pAudioBufferList=NULL;
((ma_AudioComponentInstanceDispose_proc)Mc->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
Mr ma_result_from_OSStatus(status);
}
#if defined(MA_APPLE_DESKTOP)
ma_get_AudioObject_name(Mc,deviceObjectID,sizeof(pData->deviceName),pData->deviceName);
#else
if (deviceType==Mt) {
ma_strcpy_s(pData->deviceName,sizeof(pData->deviceName),MA_DEFAULT_PLAYBACK_DEVICE_NAME);
} else {
ma_strcpy_s(pData->deviceName,sizeof(pData->deviceName),MA_DEFAULT_CAPTURE_DEVICE_NAME);
}
#endif
Mr Mf;
}
#if defined(MA_APPLE_DESKTOP)
static Me ma_device_reinit_internal__coreaudio(ma_device*Md,ma_device_type deviceType,ma_bool32 disposePreviousAudioUnit)
{
ma_device_init_internal_data__coreaudio data;
Me Mf;
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
data.allowNominalSampleRateChange=MA_FALSE;
if (deviceType==ma_device_type_capture) {
data.formatIn=Md->capture.format;
data.channelsIn=Md->capture.Mh;
data.sampleRateIn=Md->sampleRate;
MA_COPY_MEMORY(data.channelMapIn,Md->capture.channelMap,sizeof(Md->capture.channelMap));
data.shareMode=Md->capture.shareMode;
data.performanceProfile=Md->coreaudio.originalPerformanceProfile;
data.registerStopEvent=MA_TRUE;
if (disposePreviousAudioUnit) {
((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitCapture);
((ma_AudioComponentInstanceDispose_proc)Md->Mc->coreaudio.AudioComponentInstanceDispose)((AudioUnit)Md->coreaudio.audioUnitCapture);
}
if (Md->coreaudio.pAudioBufferList) {
ma_free(Md->coreaudio.pAudioBufferList,&Md->Mc->allocationCallbacks);
}
} else if (deviceType==Mt) {
data.formatIn=Md->playback.format;
data.channelsIn=Md->playback.Mh;
data.sampleRateIn=Md->sampleRate;
MA_COPY_MEMORY(data.channelMapIn,Md->playback.channelMap,sizeof(Md->playback.channelMap));
data.shareMode=Md->playback.shareMode;
data.performanceProfile=Md->coreaudio.originalPerformanceProfile;
data.registerStopEvent=(Md->type !=ma_device_type_duplex);
if (disposePreviousAudioUnit) {
((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitPlayback);
((ma_AudioComponentInstanceDispose_proc)Md->Mc->coreaudio.AudioComponentInstanceDispose)((AudioUnit)Md->coreaudio.audioUnitPlayback);
}
}
data.periodSizeInFramesIn=Md->coreaudio.originalPeriodSizeInFrames;
data.periodSizeInMillisecondsIn=Md->coreaudio.originalPeriodSizeInMilliseconds;
data.periodsIn=Md->coreaudio.originalPeriods;
if (data.periodsIn<3&&Md->type==ma_device_type_duplex) {
data.periodsIn=3;
}
Mf=ma_device_init_internal__coreaudio(Md->Mc,deviceType,NULL,&data,(Mv*)Md);
if (Mf !=Ms) {
Mr Mf;
}
if (deviceType==ma_device_type_capture) {
#if defined(MA_APPLE_DESKTOP)
Md->coreaudio.deviceObjectIDCapture=(M3)data.deviceObjectID;
ma_get_AudioObject_uid(Md->Mc,Md->coreaudio.deviceObjectIDCapture,sizeof(Md->capture.id.coreaudio),Md->capture.id.coreaudio);
#endif
Md->coreaudio.audioUnitCapture=(ma_ptr)data.audioUnit;
Md->coreaudio.pAudioBufferList=(ma_ptr)data.pAudioBufferList;
Md->coreaudio.audioBufferCapInFrames=data.periodSizeInFramesOut;
Md->capture.internalFormat=data.formatOut;
Md->capture.internalChannels=data.channelsOut;
Md->capture.internalSampleRate=data.sampleRateOut;
MA_COPY_MEMORY(Md->capture.internalChannelMap,data.channelMapOut,sizeof(data.channelMapOut));
Md->capture.internalPeriodSizeInFrames=data.periodSizeInFramesOut;
Md->capture.internalPeriods=data.periodsOut;
} else if (deviceType==Mt) {
#if defined(MA_APPLE_DESKTOP)
Md->coreaudio.deviceObjectIDPlayback=(M3)data.deviceObjectID;
ma_get_AudioObject_uid(Md->Mc,Md->coreaudio.deviceObjectIDPlayback,sizeof(Md->playback.id.coreaudio),Md->playback.id.coreaudio);
#endif
Md->coreaudio.audioUnitPlayback=(ma_ptr)data.audioUnit;
Md->playback.internalFormat=data.formatOut;
Md->playback.internalChannels=data.channelsOut;
Md->playback.internalSampleRate=data.sampleRateOut;
MA_COPY_MEMORY(Md->playback.internalChannelMap,data.channelMapOut,sizeof(data.channelMapOut));
Md->playback.internalPeriodSizeInFrames=data.periodSizeInFramesOut;
Md->playback.internalPeriods=data.periodsOut;
}
Mr Ms;
}
#endif
static Me ma_device_init__coreaudio(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
MA_ASSERT(Md !=NULL);
MA_ASSERT(Mo !=NULL);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->shareMode==ma_share_mode_exclusive)) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
ma_device_init_internal_data__coreaudio data;
data.allowNominalSampleRateChange=Mo->coreaudio.allowNominalSampleRateChange;
data.formatIn=pDescriptorCapture->format;
data.channelsIn=pDescriptorCapture->Mh;
data.sampleRateIn=pDescriptorCapture->sampleRate;
MA_COPY_MEMORY(data.channelMapIn,pDescriptorCapture->channelMap,sizeof(pDescriptorCapture->channelMap));
data.periodSizeInFramesIn=pDescriptorCapture->periodSizeInFrames;
data.periodSizeInMillisecondsIn=pDescriptorCapture->periodSizeInMilliseconds;
data.periodsIn=pDescriptorCapture->periodCount;
data.shareMode=pDescriptorCapture->shareMode;
data.performanceProfile=Mo->performanceProfile;
data.registerStopEvent=MA_TRUE;
if (data.periodsIn<3&&Mo->deviceType==ma_device_type_duplex) {
data.periodsIn=3;
}
Mf=ma_device_init_internal__coreaudio(Md->Mc,ma_device_type_capture,pDescriptorCapture->pDeviceID,&data,(Mv*)Md);
if (Mf !=Ms) {
Mr Mf;
}
Md->coreaudio.isDefaultCaptureDevice=(Mo->capture.pDeviceID==NULL);
#if defined(MA_APPLE_DESKTOP)
Md->coreaudio.deviceObjectIDCapture=(M3)data.deviceObjectID;
#endif
Md->coreaudio.audioUnitCapture=(ma_ptr)data.audioUnit;
Md->coreaudio.pAudioBufferList=(ma_ptr)data.pAudioBufferList;
Md->coreaudio.audioBufferCapInFrames=data.periodSizeInFramesOut;
Md->coreaudio.originalPeriodSizeInFrames=pDescriptorCapture->periodSizeInFrames;
Md->coreaudio.originalPeriodSizeInMilliseconds=pDescriptorCapture->periodSizeInMilliseconds;
Md->coreaudio.originalPeriods=pDescriptorCapture->periodCount;
Md->coreaudio.originalPerformanceProfile=Mo->performanceProfile;
pDescriptorCapture->format=data.formatOut;
pDescriptorCapture->Mh=data.channelsOut;
pDescriptorCapture->sampleRate=data.sampleRateOut;
MA_COPY_MEMORY(pDescriptorCapture->channelMap,data.channelMapOut,sizeof(data.channelMapOut));
pDescriptorCapture->periodSizeInFrames=data.periodSizeInFramesOut;
pDescriptorCapture->periodCount=data.periodsOut;
#if defined(MA_APPLE_DESKTOP)
ma_get_AudioObject_uid(Md->Mc,Md->coreaudio.deviceObjectIDCapture,sizeof(Md->capture.id.coreaudio),Md->capture.id.coreaudio);
if (Mo->capture.pDeviceID==NULL) {
ma_device__track__coreaudio(Md);
}
#endif
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
ma_device_init_internal_data__coreaudio data;
data.allowNominalSampleRateChange=Mo->coreaudio.allowNominalSampleRateChange;
data.formatIn=Mp->format;
data.channelsIn=Mp->Mh;
data.sampleRateIn=Mp->sampleRate;
MA_COPY_MEMORY(data.channelMapIn,Mp->channelMap,sizeof(Mp->channelMap));
data.shareMode=Mp->shareMode;
data.performanceProfile=Mo->performanceProfile;
if (Mo->deviceType==ma_device_type_duplex) {
data.periodSizeInFramesIn=pDescriptorCapture->periodSizeInFrames;
data.periodsIn=pDescriptorCapture->periodCount;
data.registerStopEvent=MA_FALSE;
} else {
data.periodSizeInFramesIn=Mp->periodSizeInFrames;
data.periodSizeInMillisecondsIn=Mp->periodSizeInMilliseconds;
data.periodsIn=Mp->periodCount;
data.registerStopEvent=MA_TRUE;
}
Mf=ma_device_init_internal__coreaudio(Md->Mc,Mt,Mp->pDeviceID,&data,(Mv*)Md);
if (Mf !=Ms) {
if (Mo->deviceType==ma_device_type_duplex) {
((ma_AudioComponentInstanceDispose_proc)Md->Mc->coreaudio.AudioComponentInstanceDispose)((AudioUnit)Md->coreaudio.audioUnitCapture);
if (Md->coreaudio.pAudioBufferList) {
 ma_free(Md->coreaudio.pAudioBufferList,&Md->Mc->allocationCallbacks);
}
}
Mr Mf;
}
Md->coreaudio.isDefaultPlaybackDevice=(Mo->playback.pDeviceID==NULL);
#if defined(MA_APPLE_DESKTOP)
Md->coreaudio.deviceObjectIDPlayback=(M3)data.deviceObjectID;
#endif
Md->coreaudio.audioUnitPlayback=(ma_ptr)data.audioUnit;
Md->coreaudio.originalPeriodSizeInFrames=Mp->periodSizeInFrames;
Md->coreaudio.originalPeriodSizeInMilliseconds=Mp->periodSizeInMilliseconds;
Md->coreaudio.originalPeriods=Mp->periodCount;
Md->coreaudio.originalPerformanceProfile=Mo->performanceProfile;
Mp->format=data.formatOut;
Mp->Mh=data.channelsOut;
Mp->sampleRate=data.sampleRateOut;
MA_COPY_MEMORY(Mp->channelMap,data.channelMapOut,sizeof(data.channelMapOut));
Mp->periodSizeInFrames=data.periodSizeInFramesOut;
Mp->periodCount=data.periodsOut;
#if defined(MA_APPLE_DESKTOP)
ma_get_AudioObject_uid(Md->Mc,Md->coreaudio.deviceObjectIDPlayback,sizeof(Md->playback.id.coreaudio),Md->playback.id.coreaudio);
if (Mp->pDeviceID==NULL&&(Mo->deviceType !=ma_device_type_duplex||pDescriptorCapture->pDeviceID !=NULL)) {
ma_device__track__coreaudio(Md);
}
#endif
}
ma_event_init(&Md->coreaudio.stopEvent);
#if defined(MA_APPLE_MOBILE)
Md->coreaudio.pNotificationHandler=(MA_BRIDGE_RETAINED Mv*)[[ma_ios_notification_handler alloc] init:Md];
#endif
Mr Ms;
}
static Me ma_device_start__coreaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
OSStatus status=((ma_AudioOutputUnitStart_proc)Md->Mc->coreaudio.AudioOutputUnitStart)((AudioUnit)Md->coreaudio.audioUnitCapture);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
OSStatus status=((ma_AudioOutputUnitStart_proc)Md->Mc->coreaudio.AudioOutputUnitStart)((AudioUnit)Md->coreaudio.audioUnitPlayback);
if (status !=noErr) {
if (Md->type==ma_device_type_duplex) {
((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitCapture);
}
Mr ma_result_from_OSStatus(status);
}
}
Mr Ms;
}
static Me ma_device_stop__coreaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
OSStatus status=((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitCapture);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
OSStatus status=((ma_AudioOutputUnitStop_proc)Md->Mc->coreaudio.AudioOutputUnitStop)((AudioUnit)Md->coreaudio.audioUnitPlayback);
if (status !=noErr) {
Mr ma_result_from_OSStatus(status);
}
}
ma_event_wait(&Md->coreaudio.stopEvent);
Mr Ms;
}
static Me ma_context_uninit__coreaudio(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_coreaudio);
#if defined(MA_APPLE_MOBILE)
if (!Mc->coreaudio.noAudioSessionDeactivate) {
if (![[AVAudioSession sharedInstance] setActive:false error:nil]) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session.");
Mr MA_FAILED_TO_INIT_BACKEND;
}
}
#endif
#if !defined(MA_NO_RUNTIME_LINKING)&&!defined(MA_APPLE_MOBILE)
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hAudioUnit);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreAudio);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreFoundation);
#endif
#if !defined(MA_APPLE_MOBILE)
ma_context__uninit_device_tracking__coreaudio(Mc);
#endif
(Mv)Mc;
Mr Ms;
}
#if defined(MA_APPLE_MOBILE)&&defined(__IPHONE_12_0)
static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_category category)
{
MA_ASSERT(category !=ma_ios_session_category_default);
MA_ASSERT(category !=ma_ios_session_category_none);
switch (category) {
case ma_ios_session_category_ambient:Mr AVAudioSessionCategoryAmbient;
case ma_ios_session_category_solo_ambient:Mr AVAudioSessionCategorySoloAmbient;
case ma_ios_session_category_playback:Mr AVAudioSessionCategoryPlayback;
case ma_ios_session_category_record:Mr AVAudioSessionCategoryRecord;
case ma_ios_session_category_play_and_record:Mr AVAudioSessionCategoryPlayAndRecord;
case ma_ios_session_category_multi_route:Mr AVAudioSessionCategoryMultiRoute;
case ma_ios_session_category_none:Mr AVAudioSessionCategoryAmbient;
case ma_ios_session_category_default:Mr AVAudioSessionCategoryAmbient;
default:Mr AVAudioSessionCategoryAmbient;
}
}
#endif
static Me ma_context_init__coreaudio(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
#if !defined(MA_APPLE_MOBILE)
Me Mf;
#endif
MA_ASSERT(Mo !=NULL);
MA_ASSERT(Mc !=NULL);
#if defined(MA_APPLE_MOBILE)
@autoreleasepool {
AVAudioSession*pAudioSession=[AVAudioSession sharedInstance];
AVAudioSessionCategoryOptions options=Mo->coreaudio.sessionCategoryOptions;
MA_ASSERT(pAudioSession !=NULL);
if (Mo->coreaudio.sessionCategory==ma_ios_session_category_default) {
#if !defined(MA_APPLE_TV)&&!defined(MA_APPLE_WATCH)
options|=AVAudioSessionCategoryOptionDefaultToSpeaker;
#endif
if ([pAudioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil]) {
} else if ([pAudioSession setCategory:AVAudioSessionCategoryPlayback withOptions:options error:nil]) {
} else if ([pAudioSession setCategory:AVAudioSessionCategoryRecord withOptions:options error:nil]) {
} else {
}
} else {
if (Mo->coreaudio.sessionCategory !=ma_ios_session_category_none) {
#if defined(__IPHONE_12_0)
if (![pAudioSession setCategory:ma_to_AVAudioSessionCategory(Mo->coreaudio.sessionCategory) withOptions:options error:nil]) {
 Mr MA_INVALID_OPERATION;
}
#else
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "Session category only supported in iOS 12 and newer.");
#endif
}
}
if (!Mo->coreaudio.noAudioSessionActivate) {
if (![pAudioSession setActive:true error:nil]) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "Failed to activate audio session.");
Mr MA_FAILED_TO_INIT_BACKEND;
}
}
}
#endif
#if !defined(MA_NO_RUNTIME_LINKING)&&!defined(MA_APPLE_MOBILE)
Mc->coreaudio.hCoreFoundation = ma_dlopen(ma_context_get_log(Mc), "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation");
if (Mc->coreaudio.hCoreFoundation==NULL) {
Mr MA_API_NOT_FOUND;
}
Mc->coreaudio.CFStringGetCString = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreFoundation, "CFStringGetCString");
Mc->coreaudio.CFRelease = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreFoundation, "CFRelease");
Mc->coreaudio.hCoreAudio = ma_dlopen(ma_context_get_log(Mc), "/System/Library/Frameworks/CoreAudio.framework/CoreAudio");
if (Mc->coreaudio.hCoreAudio==NULL) {
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreFoundation);
Mr MA_API_NOT_FOUND;
}
Mc->coreaudio.AudioObjectGetPropertyData = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
Mc->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
Mc->coreaudio.AudioObjectSetPropertyData = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
Mc->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
Mc->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");
Mc->coreaudio.hAudioUnit = ma_dlopen(ma_context_get_log(Mc), "/System/Library/Frameworks/AudioUnit.framework/AudioUnit");
if (Mc->coreaudio.hAudioUnit==NULL) {
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreAudio);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreFoundation);
Mr MA_API_NOT_FOUND;
}
if (ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) {
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hAudioUnit);
Mc->coreaudio.hAudioUnit = ma_dlopen(ma_context_get_log(Mc), "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox");
if (Mc->coreaudio.hAudioUnit==NULL) {
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreAudio);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreFoundation);
Mr MA_API_NOT_FOUND;
}
}
Mc->coreaudio.AudioComponentFindNext = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioComponentFindNext");
Mc->coreaudio.AudioComponentInstanceDispose = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioComponentInstanceDispose");
Mc->coreaudio.AudioComponentInstanceNew = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioComponentInstanceNew");
Mc->coreaudio.AudioOutputUnitStart = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioOutputUnitStart");
Mc->coreaudio.AudioOutputUnitStop = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioOutputUnitStop");
Mc->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener");
Mc->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo");
Mc->coreaudio.AudioUnitGetProperty = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioUnitGetProperty");
Mc->coreaudio.AudioUnitSetProperty = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioUnitSetProperty");
Mc->coreaudio.AudioUnitInitialize = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioUnitInitialize");
Mc->coreaudio.AudioUnitRender = ma_dlsym(ma_context_get_log(Mc), Mc->coreaudio.hAudioUnit, "AudioUnitRender");
#else
Mc->coreaudio.CFStringGetCString=(ma_proc)CFStringGetCString;
Mc->coreaudio.CFRelease=(ma_proc)CFRelease;
#if defined(MA_APPLE_DESKTOP)
Mc->coreaudio.AudioObjectGetPropertyData=(ma_proc)AudioObjectGetPropertyData;
Mc->coreaudio.AudioObjectGetPropertyDataSize=(ma_proc)AudioObjectGetPropertyDataSize;
Mc->coreaudio.AudioObjectSetPropertyData=(ma_proc)AudioObjectSetPropertyData;
Mc->coreaudio.AudioObjectAddPropertyListener=(ma_proc)AudioObjectAddPropertyListener;
Mc->coreaudio.AudioObjectRemovePropertyListener=(ma_proc)AudioObjectRemovePropertyListener;
#endif
Mc->coreaudio.AudioComponentFindNext=(ma_proc)AudioComponentFindNext;
Mc->coreaudio.AudioComponentInstanceDispose=(ma_proc)AudioComponentInstanceDispose;
Mc->coreaudio.AudioComponentInstanceNew=(ma_proc)AudioComponentInstanceNew;
Mc->coreaudio.AudioOutputUnitStart=(ma_proc)AudioOutputUnitStart;
Mc->coreaudio.AudioOutputUnitStop=(ma_proc)AudioOutputUnitStop;
Mc->coreaudio.AudioUnitAddPropertyListener=(ma_proc)AudioUnitAddPropertyListener;
Mc->coreaudio.AudioUnitGetPropertyInfo=(ma_proc)AudioUnitGetPropertyInfo;
Mc->coreaudio.AudioUnitGetProperty=(ma_proc)AudioUnitGetProperty;
Mc->coreaudio.AudioUnitSetProperty=(ma_proc)AudioUnitSetProperty;
Mc->coreaudio.AudioUnitInitialize=(ma_proc)AudioUnitInitialize;
Mc->coreaudio.AudioUnitRender=(ma_proc)AudioUnitRender;
#endif
{
AudioComponentDescription desc;
desc.componentType=kAudioUnitType_Output;
#if defined(MA_APPLE_DESKTOP)
desc.componentSubType=kAudioUnitSubType_HALOutput;
#else
desc.componentSubType=kAudioUnitSubType_RemoteIO;
#endif
desc.componentManufacturer=kAudioUnitManufacturer_Apple;
desc.componentFlags=0;
desc.componentFlagsMask=0;
Mc->coreaudio.component=((ma_AudioComponentFindNext_proc)Mc->coreaudio.AudioComponentFindNext)(NULL,&desc);
if (Mc->coreaudio.component==NULL) {
#if !defined(MA_NO_RUNTIME_LINKING)&&!defined(MA_APPLE_MOBILE)
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hAudioUnit);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreAudio);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreFoundation);
#endif
Mr MA_FAILED_TO_INIT_BACKEND;
}
}
#if !defined(MA_APPLE_MOBILE)
Mf=ma_context__init_device_tracking__coreaudio(Mc);
if (Mf !=Ms) {
#if !defined(MA_NO_RUNTIME_LINKING)&&!defined(MA_APPLE_MOBILE)
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hAudioUnit);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreAudio);
ma_dlclose(ma_context_get_log(Mc),Mc->coreaudio.hCoreFoundation);
#endif
Mr Mf;
}
#endif
Mc->coreaudio.noAudioSessionDeactivate=Mo->coreaudio.noAudioSessionDeactivate;
pCallbacks->onContextInit=ma_context_init__coreaudio;
pCallbacks->onContextUninit=ma_context_uninit__coreaudio;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__coreaudio;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__coreaudio;
pCallbacks->onDeviceInit=ma_device_init__coreaudio;
pCallbacks->onDeviceUninit=ma_device_uninit__coreaudio;
pCallbacks->onDeviceStart=ma_device_start__coreaudio;
pCallbacks->onDeviceStop=ma_device_stop__coreaudio;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#ifdef MA_HAS_SNDIO
#include <fcntl.h>
#if 0
#if defined(__NetBSD__)||defined(__OpenBSD__)
#include <sys/audioio.h>
#endif
#if defined(__FreeBSD__)||defined(__DragonFly__)
#include <sys/soundcard.h>
#endif
#endif
#define MA_SIO_DEVANY "default"
#define MA_SIO_PLAY 1
#define MA_SIO_REC 2
#define MA_SIO_NENC 8
#define MA_SIO_NCHAN 8
#define MA_SIO_NRATE 16
#define MA_SIO_NCONF 4
struct ma_sio_hdl;
struct ma_sio_par
{
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
unsigned int rchan;
unsigned int pchan;
unsigned int rate;
unsigned int bufsz;
unsigned int xrun;
unsigned int round;
unsigned int appbufsz;
int __pad[3];
unsigned int __magic;
};
struct ma_sio_enc
{
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
};
struct ma_sio_conf
{
unsigned int enc;
unsigned int rchan;
unsigned int pchan;
unsigned int rate;
};
struct ma_sio_cap
{
struct ma_sio_enc enc[MA_SIO_NENC];
unsigned int rchan[MA_SIO_NCHAN];
unsigned int pchan[MA_SIO_NCHAN];
unsigned int rate[MA_SIO_NRATE];
int __pad[7];
unsigned int nconf;
struct ma_sio_conf confs[MA_SIO_NCONF];
};
typedef struct ma_sio_hdl*(*ma_sio_open_proc) (const char*,unsigned int,int);
typedef Mv (*ma_sio_close_proc) (struct ma_sio_hdl*);
typedef int (*ma_sio_setpar_proc) (struct ma_sio_hdl*,struct ma_sio_par*);
typedef int (*ma_sio_getpar_proc) (struct ma_sio_hdl*,struct ma_sio_par*);
typedef int (*ma_sio_getcap_proc) (struct ma_sio_hdl*,struct ma_sio_cap*);
typedef size_t (*ma_sio_write_proc) (struct ma_sio_hdl*,const Mv*,size_t);
typedef size_t (*ma_sio_read_proc) (struct ma_sio_hdl*,Mv*,size_t);
typedef int (*ma_sio_start_proc) (struct ma_sio_hdl*);
typedef int (*ma_sio_stop_proc) (struct ma_sio_hdl*);
typedef int (*ma_sio_initpar_proc)(struct ma_sio_par*);
static M3 ma_get_standard_sample_rate_priority_index__sndio(M3 sampleRate)
{
M3 i;
for (i=0; i<ma_countof(g_maStandardSampleRatePriorities);++i) {
if (g_maStandardSampleRatePriorities[i]==sampleRate) {
Mr i;
}
}
Mr (M3)-1;
}
static ma_format ma_format_from_sio_enc__sndio(unsigned int bits,unsigned int bps,unsigned int sig,unsigned int le,unsigned int msb)
{
if ((ma_is_little_endian()&&le==0)||(ma_is_big_endian()&&le==1)) {
Mr ma_format_unknown;
}
if (bits==8&&bps==1&&sig==0) {
Mr ma_format_u8;
}
if (bits==16&&bps==2&&sig==1) {
Mr ma_format_s16;
}
if (bits==24&&bps==3&&sig==1) {
Mr ma_format_s24;
}
if (bits==24&&bps==4&&sig==1&&msb==0) {
}
if (bits==32&&bps==4&&sig==1) {
Mr ma_format_s32;
}
Mr ma_format_unknown;
}
static ma_format ma_find_best_format_from_sio_cap__sndio(struct ma_sio_cap*caps)
{
ma_format bestFormat;
unsigned int iConfig;
MA_ASSERT(caps !=NULL);
bestFormat=ma_format_unknown;
for (iConfig=0; iConfig<caps->nconf; iConfig+=1) {
unsigned int iEncoding;
for (iEncoding=0; iEncoding<MA_SIO_NENC; iEncoding+=1) {
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
ma_format format;
if ((caps->confs[iConfig].enc&(1UL<<iEncoding))==0) {
continue;
}
bits=caps->enc[iEncoding].bits;
bps=caps->enc[iEncoding].bps;
sig=caps->enc[iEncoding].sig;
le=caps->enc[iEncoding].le;
msb=caps->enc[iEncoding].msb;
format=ma_format_from_sio_enc__sndio(bits,bps,sig,le,msb);
if (format==ma_format_unknown) {
continue;
}
if (bestFormat==ma_format_unknown) {
bestFormat=format;
} else {
if (ma_get_format_priority_index(bestFormat)>ma_get_format_priority_index(format)) {
 bestFormat=format;
}
}
}
}
Mr bestFormat;
}
static M3 ma_find_best_channels_from_sio_cap__sndio(struct ma_sio_cap*caps,ma_device_type deviceType,ma_format requiredFormat)
{
M3 maxChannels;
unsigned int iConfig;
MA_ASSERT(caps !=NULL);
MA_ASSERT(requiredFormat !=ma_format_unknown);
maxChannels=0;
for (iConfig=0; iConfig<caps->nconf; iConfig+=1) {
unsigned int iEncoding;
for (iEncoding=0; iEncoding<MA_SIO_NENC; iEncoding+=1) {
unsigned int iChannel;
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
ma_format format;
if ((caps->confs[iConfig].enc&(1UL<<iEncoding))==0) {
continue;
}
bits=caps->enc[iEncoding].bits;
bps=caps->enc[iEncoding].bps;
sig=caps->enc[iEncoding].sig;
le=caps->enc[iEncoding].le;
msb=caps->enc[iEncoding].msb;
format=ma_format_from_sio_enc__sndio(bits,bps,sig,le,msb);
if (format !=requiredFormat) {
continue;
}
for (iChannel=0; iChannel<MA_SIO_NCHAN; iChannel+=1) {
unsigned int chan=0;
unsigned int Mh;
if (deviceType==Mt) {
 chan=caps->confs[iConfig].pchan;
} else {
 chan=caps->confs[iConfig].rchan;
}
if ((chan&(1UL<<iChannel))==0) {
 continue;
}
if (deviceType==Mt) {
 Mh=caps->pchan[iChannel];
} else {
 Mh=caps->rchan[iChannel];
}
if (maxChannels<Mh) {
 maxChannels=Mh;
}
}
}
}
Mr maxChannels;
}
static M3 ma_find_best_sample_rate_from_sio_cap__sndio(struct ma_sio_cap*caps,ma_device_type deviceType,ma_format requiredFormat,M3 requiredChannels)
{
M3 firstSampleRate;
M3 bestSampleRate;
unsigned int iConfig;
MA_ASSERT(caps !=NULL);
MA_ASSERT(requiredFormat !=ma_format_unknown);
MA_ASSERT(requiredChannels>0);
MA_ASSERT(requiredChannels<=MA_MAX_CHANNELS);
firstSampleRate=0;
bestSampleRate=0;
for (iConfig=0; iConfig<caps->nconf; iConfig+=1) {
unsigned int iEncoding;
for (iEncoding=0; iEncoding<MA_SIO_NENC; iEncoding+=1) {
unsigned int iChannel;
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
ma_format format;
if ((caps->confs[iConfig].enc&(1UL<<iEncoding))==0) {
continue;
}
bits=caps->enc[iEncoding].bits;
bps=caps->enc[iEncoding].bps;
sig=caps->enc[iEncoding].sig;
le=caps->enc[iEncoding].le;
msb=caps->enc[iEncoding].msb;
format=ma_format_from_sio_enc__sndio(bits,bps,sig,le,msb);
if (format !=requiredFormat) {
continue;
}
for (iChannel=0; iChannel<MA_SIO_NCHAN; iChannel+=1) {
unsigned int chan=0;
unsigned int Mh;
unsigned int iRate;
if (deviceType==Mt) {
 chan=caps->confs[iConfig].pchan;
} else {
 chan=caps->confs[iConfig].rchan;
}
if ((chan&(1UL<<iChannel))==0) {
 continue;
}
if (deviceType==Mt) {
 Mh=caps->pchan[iChannel];
} else {
 Mh=caps->rchan[iChannel];
}
if (Mh !=requiredChannels) {
 continue;
}
for (iRate=0; iRate<MA_SIO_NRATE; iRate+=1) {
 M3 rate=(M3)caps->rate[iRate];
 M3 ratePriority;
 if (firstSampleRate==0) {
 firstSampleRate=rate;
 }
 ratePriority=ma_get_standard_sample_rate_priority_index__sndio(rate);
 if (ratePriority==(M3)-1) {
 continue;
 }
 if (ma_get_standard_sample_rate_priority_index__sndio(bestSampleRate)>ratePriority) {
 bestSampleRate=rate;
 }
}
}
}
}
if (bestSampleRate==0) {
bestSampleRate=firstSampleRate;
}
Mr bestSampleRate;
}
static Me ma_context_enumerate_devices__sndio(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_bool32 isTerminating=MA_FALSE;
struct ma_sio_hdl*handle;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
if (!isTerminating) {
handle=((ma_sio_open_proc)Mc->sndio.sio_open)(MA_SIO_DEVANY,MA_SIO_PLAY,0);
if (handle !=NULL) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strcpy_s(deviceInfo.id.sndio,sizeof(deviceInfo.id.sndio),MA_SIO_DEVANY);
ma_strcpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME);
isTerminating=!callback(Mc,Mt,&deviceInfo,pUserData);
((ma_sio_close_proc)Mc->sndio.sio_close)(handle);
}
}
if (!isTerminating) {
handle=((ma_sio_open_proc)Mc->sndio.sio_open)(MA_SIO_DEVANY,MA_SIO_REC,0);
if (handle !=NULL) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), "default");
ma_strcpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_CAPTURE_DEVICE_NAME);
isTerminating=!callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
((ma_sio_close_proc)Mc->sndio.sio_close)(handle);
}
}
Mr Ms;
}
static Me ma_context_get_device_info__sndio(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
char devid[256];
struct ma_sio_hdl*handle;
struct ma_sio_cap caps;
unsigned int iConfig;
MA_ASSERT(Mc !=NULL);
if (pDeviceID==NULL) {
ma_strcpy_s(devid,sizeof(devid),MA_SIO_DEVANY);
ma_strcpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),(deviceType==Mt)?MA_DEFAULT_PLAYBACK_DEVICE_NAME:MA_DEFAULT_CAPTURE_DEVICE_NAME);
} else {
ma_strcpy_s(devid,sizeof(devid),pDeviceID->sndio);
ma_strcpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),devid);
}
handle=((ma_sio_open_proc)Mc->sndio.sio_open)(devid,(deviceType==Mt)?MA_SIO_PLAY:MA_SIO_REC,0);
if (handle==NULL) {
Mr MA_NO_DEVICE;
}
if (((ma_sio_getcap_proc)Mc->sndio.sio_getcap)(handle,&caps)==0) {
Mr MA_ERROR;
}
pDeviceInfo->nativeDataFormatCount=0;
for (iConfig=0; iConfig<caps.nconf; iConfig+=1) {
unsigned int iEncoding;
unsigned int iChannel;
unsigned int iRate;
for (iEncoding=0; iEncoding<MA_SIO_NENC; iEncoding+=1) {
unsigned int bits;
unsigned int bps;
unsigned int sig;
unsigned int le;
unsigned int msb;
ma_format format;
if ((caps.confs[iConfig].enc&(1UL<<iEncoding))==0) {
continue;
}
bits=caps.enc[iEncoding].bits;
bps=caps.enc[iEncoding].bps;
sig=caps.enc[iEncoding].sig;
le=caps.enc[iEncoding].le;
msb=caps.enc[iEncoding].msb;
format=ma_format_from_sio_enc__sndio(bits,bps,sig,le,msb);
if (format==ma_format_unknown) {
continue;
}
for (iChannel=0; iChannel<MA_SIO_NCHAN; iChannel+=1) {
unsigned int chan=0;
unsigned int Mh;
if (deviceType==Mt) {
 chan=caps.confs[iConfig].pchan;
} else {
 chan=caps.confs[iConfig].rchan;
}
if ((chan&(1UL<<iChannel))==0) {
 continue;
}
if (deviceType==Mt) {
 Mh=caps.pchan[iChannel];
} else {
 Mh=caps.rchan[iChannel];
}
for (iRate=0; iRate<MA_SIO_NRATE; iRate+=1) {
 if ((caps.confs[iConfig].rate&(1UL<<iRate)) !=0) {
 ma_device_info_add_native_data_format(pDeviceInfo,format,Mh,caps.rate[iRate],0);
 }
}
}
}
}
((ma_sio_close_proc)Mc->sndio.sio_close)(handle);
Mr Ms;
}
static Me ma_device_uninit__sndio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
((ma_sio_close_proc)Md->Mc->sndio.sio_close)((struct ma_sio_hdl*)Md->sndio.handleCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
((ma_sio_close_proc)Md->Mc->sndio.sio_close)((struct ma_sio_hdl*)Md->sndio.handlePlayback);
}
Mr Ms;
}
static Me ma_device_init_handle__sndio(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*pDescriptor,ma_device_type deviceType)
{
const char*pDeviceName;
ma_ptr handle;
int openFlags=0;
struct ma_sio_cap caps;
struct ma_sio_par par;
const ma_device_id*pDeviceID;
ma_format format;
M3 Mh;
M3 sampleRate;
ma_format internalFormat;
M3 internalChannels;
M3 internalSampleRate;
M3 internalPeriodSizeInFrames;
M3 internalPeriods;
MA_ASSERT(Mo !=NULL);
MA_ASSERT(deviceType !=ma_device_type_duplex);
MA_ASSERT(Md !=NULL);
if (deviceType==ma_device_type_capture) {
openFlags=MA_SIO_REC;
} else {
openFlags=MA_SIO_PLAY;
}
pDeviceID=pDescriptor->pDeviceID;
format=pDescriptor->format;
Mh=pDescriptor->Mh;
sampleRate=pDescriptor->sampleRate;
pDeviceName=MA_SIO_DEVANY;
if (pDeviceID !=NULL) {
pDeviceName=pDeviceID->sndio;
}
handle=(ma_ptr)((ma_sio_open_proc)Md->Mc->sndio.sio_open)(pDeviceName,openFlags,0);
if (handle==NULL) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.");
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
if (((ma_sio_getcap_proc)Md->Mc->sndio.sio_getcap)((struct ma_sio_hdl*)handle,&caps)==0) {
((ma_sio_close_proc)Md->Mc->sndio.sio_close)((struct ma_sio_hdl*)handle);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.");
Mr MA_ERROR;
}
if (deviceType==ma_device_type_capture) {
if (format==ma_format_unknown) {
format=ma_find_best_format_from_sio_cap__sndio(&caps);
}
if (Mh==0) {
if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
Mh=ma_find_best_channels_from_sio_cap__sndio(&caps,deviceType,format);
} else {
Mh=MA_DEFAULT_CHANNELS;
}
}
} else {
if (format==ma_format_unknown) {
format=ma_find_best_format_from_sio_cap__sndio(&caps);
}
if (Mh==0) {
if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
Mh=ma_find_best_channels_from_sio_cap__sndio(&caps,deviceType,format);
} else {
Mh=MA_DEFAULT_CHANNELS;
}
}
}
if (sampleRate==0) {
sampleRate=ma_find_best_sample_rate_from_sio_cap__sndio(&caps,Mo->deviceType,format,Mh);
}
((ma_sio_initpar_proc)Md->Mc->sndio.sio_initpar)(&par);
par.msb=0;
par.le=ma_is_little_endian();
switch (format) {
case ma_format_u8:
{
par.bits=8;
par.bps=1;
par.sig=0;
} break;
case ma_format_s24:
{
par.bits=24;
par.bps=3;
par.sig=1;
} break;
case ma_format_s32:
{
par.bits=32;
par.bps=4;
par.sig=1;
} break;
case ma_format_s16:
case ma_format_f32:
case ma_format_unknown:
default:
{
par.bits=16;
par.bps=2;
par.sig=1;
} break;
}
if (deviceType==ma_device_type_capture) {
par.rchan=Mh;
} else {
par.pchan=Mh;
}
par.rate=sampleRate;
internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,par.rate,Mo->performanceProfile);
par.round=internalPeriodSizeInFrames;
par.appbufsz=par.round*pDescriptor->periodCount;
if (((ma_sio_setpar_proc)Md->Mc->sndio.sio_setpar)((struct ma_sio_hdl*)handle,&par)==0) {
((ma_sio_close_proc)Md->Mc->sndio.sio_close)((struct ma_sio_hdl*)handle);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.");
Mr MA_ERROR;
}
if (((ma_sio_getpar_proc)Md->Mc->sndio.sio_getpar)((struct ma_sio_hdl*)handle,&par)==0) {
((ma_sio_close_proc)Md->Mc->sndio.sio_close)((struct ma_sio_hdl*)handle);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.");
Mr MA_ERROR;
}
internalFormat=ma_format_from_sio_enc__sndio(par.bits,par.bps,par.sig,par.le,par.msb);
internalChannels=(deviceType==ma_device_type_capture)?par.rchan:par.pchan;
internalSampleRate=par.rate;
internalPeriods=par.appbufsz / par.round;
internalPeriodSizeInFrames=par.round;
if (deviceType==ma_device_type_capture) {
Md->sndio.handleCapture=handle;
} else {
Md->sndio.handlePlayback=handle;
}
pDescriptor->format=internalFormat;
pDescriptor->Mh=internalChannels;
pDescriptor->sampleRate=internalSampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_sndio,pDescriptor->channelMap,ma_countof(pDescriptor->channelMap),internalChannels);
pDescriptor->periodSizeInFrames=internalPeriodSizeInFrames;
pDescriptor->periodCount=internalPeriods;
Mr Ms;
}
static Me ma_device_init__sndio(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->sndio);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_handle__sndio(Md,Mo,pDescriptorCapture,ma_device_type_capture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_handle__sndio(Md,Mo,Mp,Mt);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_start__sndio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
((ma_sio_start_proc)Md->Mc->sndio.sio_start)((struct ma_sio_hdl*)Md->sndio.handleCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
((ma_sio_start_proc)Md->Mc->sndio.sio_start)((struct ma_sio_hdl*)Md->sndio.handlePlayback);
}
Mr Ms;
}
static Me ma_device_stop__sndio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
((ma_sio_stop_proc)Md->Mc->sndio.sio_stop)((struct ma_sio_hdl*)Md->sndio.handleCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
((ma_sio_stop_proc)Md->Mc->sndio.sio_stop)((struct ma_sio_hdl*)Md->sndio.handlePlayback);
}
Mr Ms;
}
static Me ma_device_write__sndio(ma_device*Md,const Mv*pPCMFrames,M3 frameCount,M3*pFramesWritten)
{
int Mf;
if (pFramesWritten !=NULL) {
*pFramesWritten=0;
}
Mf=((ma_sio_write_proc)Md->Mc->sndio.sio_write)((struct ma_sio_hdl*)Md->sndio.handlePlayback,pPCMFrames,frameCount*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
if (Mf==0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.");
Mr MA_IO_ERROR;
}
if (pFramesWritten !=NULL) {
*pFramesWritten=frameCount;
}
Mr Ms;
}
static Me ma_device_read__sndio(ma_device*Md,Mv*pPCMFrames,M3 frameCount,M3*pFramesRead)
{
int Mf;
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
Mf=((ma_sio_read_proc)Md->Mc->sndio.sio_read)((struct ma_sio_hdl*)Md->sndio.handleCapture,pPCMFrames,frameCount*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels));
if (Mf==0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.");
Mr MA_IO_ERROR;
}
if (pFramesRead !=NULL) {
*pFramesRead=frameCount;
}
Mr Ms;
}
static Me ma_context_uninit__sndio(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_sndio);
(Mv)Mc;
Mr Ms;
}
static Me ma_context_init__sndio(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
#ifndef MA_NO_RUNTIME_LINKING
const char*libsndioNames[]={
"libsndio.so"
};
size_t i;
for (i=0; i<ma_countof(libsndioNames);++i) {
Mc->sndio.sndioSO=ma_dlopen(ma_context_get_log(Mc),libsndioNames[i]);
if (Mc->sndio.sndioSO !=NULL) {
break;
}
}
if (Mc->sndio.sndioSO==NULL) {
Mr MA_NO_BACKEND;
}
Mc->sndio.sio_open = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_open");
Mc->sndio.sio_close = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_close");
Mc->sndio.sio_setpar = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_setpar");
Mc->sndio.sio_getpar = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_getpar");
Mc->sndio.sio_getcap = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_getcap");
Mc->sndio.sio_write = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_write");
Mc->sndio.sio_read = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_read");
Mc->sndio.sio_start = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_start");
Mc->sndio.sio_stop = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_stop");
Mc->sndio.sio_initpar = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->sndio.sndioSO, "sio_initpar");
#else
Mc->sndio.sio_open=sio_open;
Mc->sndio.sio_close=sio_close;
Mc->sndio.sio_setpar=sio_setpar;
Mc->sndio.sio_getpar=sio_getpar;
Mc->sndio.sio_getcap=sio_getcap;
Mc->sndio.sio_write=sio_write;
Mc->sndio.sio_read=sio_read;
Mc->sndio.sio_start=sio_start;
Mc->sndio.sio_stop=sio_stop;
Mc->sndio.sio_initpar=sio_initpar;
#endif
pCallbacks->onContextInit=ma_context_init__sndio;
pCallbacks->onContextUninit=ma_context_uninit__sndio;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__sndio;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__sndio;
pCallbacks->onDeviceInit=ma_device_init__sndio;
pCallbacks->onDeviceUninit=ma_device_uninit__sndio;
pCallbacks->onDeviceStart=ma_device_start__sndio;
pCallbacks->onDeviceStop=ma_device_stop__sndio;
pCallbacks->onDeviceRead=ma_device_read__sndio;
pCallbacks->onDeviceWrite=ma_device_write__sndio;
pCallbacks->onDeviceDataLoop=NULL;
(Mv)Mo;
Mr Ms;
}
#endif
#ifdef MA_HAS_AUDIO4
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/audioio.h>
#ifdef __NetBSD__
#include <sys/param.h>
#endif
#if defined(__OpenBSD__)
#include <sys/param.h>
#if defined(OpenBSD)&&OpenBSD>=201709
#define MA_AUDIO4_USE_NEW_API
#endif
#endif
static Mv ma_construct_device_id__audio4(char*id,size_t idSize,const char*base,int deviceIndex)
{
size_t baseLen;
MA_ASSERT(id !=NULL);
MA_ASSERT(idSize>0);
MA_ASSERT(deviceIndex>=0);
baseLen=strlen(base);
MA_ASSERT(idSize>baseLen);
ma_strcpy_s(id,idSize,base);
ma_itoa_s(deviceIndex,id+baseLen,idSize-baseLen,10);
}
static Me ma_extract_device_index_from_id__audio4(const char*id,const char*base,int*pIndexOut)
{
size_t idLen;
size_t baseLen;
const char*deviceIndexStr;
MA_ASSERT(id !=NULL);
MA_ASSERT(base !=NULL);
MA_ASSERT(pIndexOut !=NULL);
idLen=strlen(id);
baseLen=strlen(base);
if (idLen<=baseLen) {
Mr MA_ERROR;
}
if (strncmp(id,base,baseLen) !=0) {
Mr MA_ERROR;
}
deviceIndexStr=id+baseLen;
if (deviceIndexStr[0]=='\0') {
Mr MA_ERROR;
}
if (pIndexOut) {
*pIndexOut=atoi(deviceIndexStr);
}
Mr Ms;
}
#if !defined(MA_AUDIO4_USE_NEW_API)
static ma_format ma_format_from_encoding__audio4(unsigned int encoding,unsigned int precision)
{
if (precision==8&&(encoding==AUDIO_ENCODING_ULINEAR||encoding==AUDIO_ENCODING_ULINEAR||encoding==AUDIO_ENCODING_ULINEAR_LE||encoding==AUDIO_ENCODING_ULINEAR_BE)) {
Mr ma_format_u8;
} else {
if (ma_is_little_endian()&&encoding==AUDIO_ENCODING_SLINEAR_LE) {
if (precision==16) {
Mr ma_format_s16;
} else if (precision==24) {
Mr ma_format_s24;
} else if (precision==32) {
Mr ma_format_s32;
}
} else if (ma_is_big_endian()&&encoding==AUDIO_ENCODING_SLINEAR_BE) {
if (precision==16) {
Mr ma_format_s16;
} else if (precision==24) {
Mr ma_format_s24;
} else if (precision==32) {
Mr ma_format_s32;
}
}
}
Mr ma_format_unknown;
}
static Mv ma_encoding_from_format__audio4(ma_format format,unsigned int*pEncoding,unsigned int*pPrecision)
{
MA_ASSERT(pEncoding !=NULL);
MA_ASSERT(pPrecision !=NULL);
switch (format)
{
case ma_format_u8:
{
*pEncoding=AUDIO_ENCODING_ULINEAR;
*pPrecision=8;
} break;
case ma_format_s24:
{
*pEncoding=(ma_is_little_endian())?AUDIO_ENCODING_SLINEAR_LE:AUDIO_ENCODING_SLINEAR_BE;
*pPrecision=24;
} break;
case ma_format_s32:
{
*pEncoding=(ma_is_little_endian())?AUDIO_ENCODING_SLINEAR_LE:AUDIO_ENCODING_SLINEAR_BE;
*pPrecision=32;
} break;
case ma_format_s16:
case ma_format_f32:
case ma_format_unknown:
default:
{
*pEncoding=(ma_is_little_endian())?AUDIO_ENCODING_SLINEAR_LE:AUDIO_ENCODING_SLINEAR_BE;
*pPrecision=16;
} break;
}
}
static ma_format ma_format_from_prinfo__audio4(struct audio_prinfo*prinfo)
{
Mr ma_format_from_encoding__audio4(prinfo->encoding,prinfo->precision);
}
static ma_format ma_best_format_from_fd__audio4(int fd,ma_format preferredFormat)
{
audio_encoding_t encoding;
M3 iFormat;
int counter=0;
if (preferredFormat !=ma_format_unknown) {
counter=0;
for (;;) {
MA_ZERO_OBJECT(&encoding);
encoding.index=counter;
if (ioctl(fd,AUDIO_GETENC,&encoding)<0) {
break;
}
if (preferredFormat==ma_format_from_encoding__audio4(encoding.encoding,encoding.precision)) {
Mr preferredFormat;
}
counter+=1;
}
}
for (iFormat=0; iFormat<ma_countof(g_maFormatPriorities); iFormat+=1) {
ma_format format=g_maFormatPriorities[iFormat];
counter=0;
for (;;) {
MA_ZERO_OBJECT(&encoding);
encoding.index=counter;
if (ioctl(fd,AUDIO_GETENC,&encoding)<0) {
break;
}
if (format==ma_format_from_encoding__audio4(encoding.encoding,encoding.precision)) {
Mr format;
}
counter+=1;
}
}
Mr ma_format_unknown;
}
#else
static ma_format ma_format_from_swpar__audio4(struct audio_swpar*par)
{
if (par->bits==8&&par->bps==1&&par->sig==0) {
Mr ma_format_u8;
}
if (par->bits==16&&par->bps==2&&par->sig==1&&par->le==ma_is_little_endian()) {
Mr ma_format_s16;
}
if (par->bits==24&&par->bps==3&&par->sig==1&&par->le==ma_is_little_endian()) {
Mr ma_format_s24;
}
if (par->bits==32&&par->bps==4&&par->sig==1&&par->le==ma_is_little_endian()) {
Mr ma_format_f32;
}
Mr ma_format_unknown;
}
#endif
static Me ma_context_get_device_info_from_fd__audio4(ma_context*Mc,ma_device_type deviceType,int fd,ma_device_info*pDeviceInfo)
{
audio_device_t fdDevice;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(fd>=0);
MA_ASSERT(pDeviceInfo !=NULL);
(Mv)Mc;
(Mv)deviceType;
if (ioctl(fd,AUDIO_GETDEV,&fdDevice)<0) {
Mr MA_ERROR;
}
ma_strcpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),fdDevice.name);
#if !defined(MA_AUDIO4_USE_NEW_API)
{
audio_info_t fdInfo;
int counter=0;
M3 Mh;
M3 sampleRate;
#if defined(__NetBSD__)&&(__NetBSD_Version__>=900000000)
if (ioctl(fd,AUDIO_GETFORMAT,&fdInfo)<0) {
Mr MA_ERROR;
}
#else
if (ioctl(fd,AUDIO_GETINFO,&fdInfo)<0) {
Mr MA_ERROR;
}
#endif
if (deviceType==Mt) {
Mh=fdInfo.play.Mh;
sampleRate=fdInfo.play.sample_rate;
} else {
Mh=fdInfo.record.Mh;
sampleRate=fdInfo.record.sample_rate;
}
pDeviceInfo->nativeDataFormatCount=0;
for (;;) {
audio_encoding_t encoding;
ma_format format;
MA_ZERO_OBJECT(&encoding);
encoding.index=counter;
if (ioctl(fd,AUDIO_GETENC,&encoding)<0) {
break;
}
format=ma_format_from_encoding__audio4(encoding.encoding,encoding.precision);
if (format !=ma_format_unknown) {
ma_device_info_add_native_data_format(pDeviceInfo,format,Mh,sampleRate,0);
}
counter+=1;
}
}
#else
{
struct audio_swpar fdPar;
ma_format format;
M3 Mh;
M3 sampleRate;
if (ioctl(fd,AUDIO_GETPAR,&fdPar)<0) {
Mr MA_ERROR;
}
format=ma_format_from_swpar__audio4(&fdPar);
if (format==ma_format_unknown) {
Mr MA_FORMAT_NOT_SUPPORTED;
}
if (deviceType==Mt) {
Mh=fdPar.pchan;
} else {
Mh=fdPar.rchan;
}
sampleRate=fdPar.rate;
pDeviceInfo->nativeDataFormatCount=0;
ma_device_info_add_native_data_format(pDeviceInfo,format,Mh,sampleRate,0);
}
#endif
Mr Ms;
}
static Me ma_context_enumerate_devices__audio4(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
const int maxDevices=64;
char devpath[256];
int iDevice;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
for (iDevice=0; iDevice<maxDevices;++iDevice) {
struct stat st;
int fd;
ma_bool32 isTerminating=MA_FALSE;
ma_strcpy_s(devpath, sizeof(devpath), "/dev/audioctl");
ma_itoa_s(iDevice,devpath+strlen(devpath),sizeof(devpath)-strlen(devpath),10);
if (stat(devpath,&st)<0) {
break;
}
if (!isTerminating) {
fd=open(devpath,O_RDONLY,0);
if (fd>=0) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
if (ma_context_get_device_info_from_fd__audio4(Mc,Mt,fd,&deviceInfo)==Ms) {
 isTerminating=!callback(Mc,Mt,&deviceInfo,pUserData);
}
close(fd);
}
}
if (!isTerminating) {
fd=open(devpath,O_WRONLY,0);
if (fd>=0) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
if (ma_context_get_device_info_from_fd__audio4(Mc,ma_device_type_capture,fd,&deviceInfo)==Ms) {
 isTerminating=!callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
close(fd);
}
}
if (isTerminating) {
break;
}
}
Mr Ms;
}
static Me ma_context_get_device_info__audio4(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
int fd=-1;
int deviceIndex=-1;
char ctlid[256];
Me Mf;
MA_ASSERT(Mc !=NULL);
if (pDeviceID==NULL) {
ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl");
} else {
Mf = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex);
if (Mf !=Ms) {
Mr Mf;
}
ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex);
}
fd=open(ctlid,(deviceType==Mt)?O_WRONLY:O_RDONLY,0);
if (fd==-1) {
Mr MA_NO_DEVICE;
}
if (deviceIndex==-1) {
ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio");
} else {
ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex);
}
Mf=ma_context_get_device_info_from_fd__audio4(Mc,deviceType,fd,pDeviceInfo);
close(fd);
Mr Mf;
}
static Me ma_device_uninit__audio4(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
close(Md->audio4.fdCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
close(Md->audio4.fdPlayback);
}
Mr Ms;
}
static Me ma_device_init_fd__audio4(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*pDescriptor,ma_device_type deviceType)
{
const char*pDefaultDeviceNames[]={
"/dev/audio","/dev/audio0"
};
const char*pDefaultDeviceCtlNames[]={
"/dev/audioctl","/dev/audioctl0"
};
int fd;
int fdFlags=0;
size_t iDefaultDevice=(size_t)-1;
ma_format internalFormat;
M3 internalChannels;
M3 internalSampleRate;
M3 internalPeriodSizeInFrames;
M3 internalPeriods;
MA_ASSERT(Mo !=NULL);
MA_ASSERT(deviceType !=ma_device_type_duplex);
MA_ASSERT(Md !=NULL);
if (deviceType==ma_device_type_capture) {
fdFlags=O_RDONLY;
} else {
fdFlags=O_WRONLY;
}
if (pDescriptor->pDeviceID==NULL) {
for (iDefaultDevice=0; iDefaultDevice<ma_countof(pDefaultDeviceNames);++iDefaultDevice) {
fd=open(pDefaultDeviceNames[iDefaultDevice],fdFlags,0);
if (fd !=-1) {
break;
}
}
} else {
fd=open(pDescriptor->pDeviceID->audio4,fdFlags,0);
for (iDefaultDevice=0; iDefaultDevice<ma_countof(pDefaultDeviceNames); iDefaultDevice+=1) {
if (ma_strcmp(pDefaultDeviceNames[iDefaultDevice],pDescriptor->pDeviceID->audio4)==0) {
break;
}
}
if (iDefaultDevice==ma_countof(pDefaultDeviceNames)) {
iDefaultDevice=(size_t)-1;
}
}
if (fd==-1) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.");
Mr ma_result_from_errno(errno);
}
#if !defined(MA_AUDIO4_USE_NEW_API)
{
audio_info_t fdInfo;
int fdInfoResult=-1;
AUDIO_INITINFO(&fdInfo);
if (iDefaultDevice !=(size_t)-1) {
int fdctl=open(pDefaultDeviceCtlNames[iDefaultDevice],fdFlags,0);
if (fdctl !=-1) {
#if defined(__NetBSD__)&&(__NetBSD_Version__>=900000000)
fdInfoResult=ioctl(fdctl,AUDIO_GETFORMAT,&fdInfo);
#else
fdInfoResult=ioctl(fdctl,AUDIO_GETINFO,&fdInfo);
#endif
close(fdctl);
}
}
if (fdInfoResult==-1) {
if (ioctl(fd,AUDIO_GETINFO,&fdInfo)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.");
Mr ma_result_from_errno(errno);
}
}
if (deviceType==ma_device_type_capture) {
fdInfo.mode=AUMODE_RECORD;
ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd,pDescriptor->format),&fdInfo.record.encoding,&fdInfo.record.precision);
if (pDescriptor->Mh !=0) {
fdInfo.record.Mh=ma_clamp(pDescriptor->Mh,1,12);
}
if (pDescriptor->sampleRate !=0) {
fdInfo.record.sample_rate=ma_clamp(pDescriptor->sampleRate,1000,192000);
}
} else {
fdInfo.mode=AUMODE_PLAY;
ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd,pDescriptor->format),&fdInfo.play.encoding,&fdInfo.play.precision);
if (pDescriptor->Mh !=0) {
fdInfo.play.Mh=ma_clamp(pDescriptor->Mh,1,12);
}
if (pDescriptor->sampleRate !=0) {
fdInfo.play.sample_rate=ma_clamp(pDescriptor->sampleRate,1000,192000);
}
}
if (ioctl(fd,AUDIO_SETINFO,&fdInfo)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.");
Mr ma_result_from_errno(errno);
}
if (ioctl(fd,AUDIO_GETINFO,&fdInfo)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.");
Mr ma_result_from_errno(errno);
}
if (deviceType==ma_device_type_capture) {
internalFormat=ma_format_from_prinfo__audio4(&fdInfo.record);
internalChannels=fdInfo.record.Mh;
internalSampleRate=fdInfo.record.sample_rate;
} else {
internalFormat=ma_format_from_prinfo__audio4(&fdInfo.play);
internalChannels=fdInfo.play.Mh;
internalSampleRate=fdInfo.play.sample_rate;
}
if (internalFormat==ma_format_unknown) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.");
Mr MA_FORMAT_NOT_SUPPORTED;
}
{
M3 internalPeriodSizeInBytes;
internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,internalSampleRate,Mo->performanceProfile);
internalPeriodSizeInBytes=internalPeriodSizeInFrames*ma_get_bytes_per_frame(internalFormat,internalChannels);
if (internalPeriodSizeInBytes<16) {
internalPeriodSizeInBytes=16;
}
internalPeriods=pDescriptor->periodCount;
if (internalPeriods<2) {
internalPeriods=2;
}
AUDIO_INITINFO(&fdInfo);
fdInfo.hiwat=internalPeriods;
fdInfo.lowat=internalPeriods-1;
fdInfo.blocksize=internalPeriodSizeInBytes;
if (ioctl(fd,AUDIO_SETINFO,&fdInfo)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.");
Mr ma_result_from_errno(errno);
}
internalPeriods=fdInfo.hiwat;
internalPeriodSizeInFrames=fdInfo.blocksize / ma_get_bytes_per_frame(internalFormat,internalChannels);
}
}
#else
{
struct audio_swpar fdPar;
if (ioctl(fd,AUDIO_GETPAR,&fdPar)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.");
Mr ma_result_from_errno(errno);
}
internalFormat=ma_format_from_swpar__audio4(&fdPar);
internalChannels=(deviceType==ma_device_type_capture)?fdPar.rchan:fdPar.pchan;
internalSampleRate=fdPar.rate;
if (internalFormat==ma_format_unknown) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.");
Mr MA_FORMAT_NOT_SUPPORTED;
}
{
M3 internalPeriodSizeInBytes;
internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,internalSampleRate,Mo->performanceProfile);
internalPeriodSizeInBytes=internalPeriodSizeInFrames*ma_get_bytes_per_frame(internalFormat,internalChannels);
if (internalPeriodSizeInBytes<16) {
internalPeriodSizeInBytes=16;
}
fdPar.nblks=pDescriptor->periodCount;
fdPar.round=internalPeriodSizeInBytes;
if (ioctl(fd,AUDIO_SETPAR,&fdPar)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.");
Mr ma_result_from_errno(errno);
}
if (ioctl(fd,AUDIO_GETPAR,&fdPar)<0) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.");
Mr ma_result_from_errno(errno);
}
}
internalFormat=ma_format_from_swpar__audio4(&fdPar);
internalChannels=(deviceType==ma_device_type_capture)?fdPar.rchan:fdPar.pchan;
internalSampleRate=fdPar.rate;
internalPeriods=fdPar.nblks;
internalPeriodSizeInFrames=fdPar.round / ma_get_bytes_per_frame(internalFormat,internalChannels);
}
#endif
if (internalFormat==ma_format_unknown) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.");
Mr MA_FORMAT_NOT_SUPPORTED;
}
if (deviceType==ma_device_type_capture) {
Md->audio4.fdCapture=fd;
} else {
Md->audio4.fdPlayback=fd;
}
pDescriptor->format=internalFormat;
pDescriptor->Mh=internalChannels;
pDescriptor->sampleRate=internalSampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_sound4,pDescriptor->channelMap,ma_countof(pDescriptor->channelMap),internalChannels);
pDescriptor->periodSizeInFrames=internalPeriodSizeInFrames;
pDescriptor->periodCount=internalPeriods;
Mr Ms;
}
static Me ma_device_init__audio4(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->audio4);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
Md->audio4.fdCapture=-1;
Md->audio4.fdPlayback=-1;
#if defined(__NetBSD_Version__)&&__NetBSD_Version__>=800000000
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->shareMode==ma_share_mode_exclusive)) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
#else
#endif
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_fd__audio4(Md,Mo,pDescriptorCapture,ma_device_type_capture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_fd__audio4(Md,Mo,Mp,Mt);
if (Mf !=Ms) {
if (Mo->deviceType==ma_device_type_duplex) {
close(Md->audio4.fdCapture);
}
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_start__audio4(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
if (Md->audio4.fdCapture==-1) {
Mr MA_INVALID_ARGS;
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
if (Md->audio4.fdPlayback==-1) {
Mr MA_INVALID_ARGS;
}
}
Mr Ms;
}
static Me ma_device_stop_fd__audio4(ma_device*Md,int fd)
{
if (fd==-1) {
Mr MA_INVALID_ARGS;
}
#if !defined(MA_AUDIO4_USE_NEW_API)
if (ioctl(fd,AUDIO_FLUSH,0)<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.");
Mr ma_result_from_errno(errno);
}
#else
if (ioctl(fd,AUDIO_STOP,0)<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.");
Mr ma_result_from_errno(errno);
}
#endif
Mr Ms;
}
static Me ma_device_stop__audio4(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
Me Mf;
Mf=ma_device_stop_fd__audio4(Md,Md->audio4.fdCapture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
Me Mf;
#if !defined(MA_AUDIO4_USE_NEW_API)
ioctl(Md->audio4.fdPlayback,AUDIO_DRAIN,0);
#endif
Mf=ma_device_stop_fd__audio4(Md,Md->audio4.fdPlayback);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_write__audio4(ma_device*Md,const Mv*pPCMFrames,M3 frameCount,M3*pFramesWritten)
{
int Mf;
if (pFramesWritten !=NULL) {
*pFramesWritten=0;
}
Mf=write(Md->audio4.fdPlayback,pPCMFrames,frameCount*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
if (Mf<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.");
Mr ma_result_from_errno(errno);
}
if (pFramesWritten !=NULL) {
*pFramesWritten=(M3)Mf / ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
}
Mr Ms;
}
static Me ma_device_read__audio4(ma_device*Md,Mv*pPCMFrames,M3 frameCount,M3*pFramesRead)
{
int Mf;
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
Mf=read(Md->audio4.fdCapture,pPCMFrames,frameCount*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels));
if (Mf<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.");
Mr ma_result_from_errno(errno);
}
if (pFramesRead !=NULL) {
*pFramesRead=(M3)Mf / ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
}
Mr Ms;
}
static Me ma_context_uninit__audio4(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_audio4);
(Mv)Mc;
Mr Ms;
}
static Me ma_context_init__audio4(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
pCallbacks->onContextInit=ma_context_init__audio4;
pCallbacks->onContextUninit=ma_context_uninit__audio4;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__audio4;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__audio4;
pCallbacks->onDeviceInit=ma_device_init__audio4;
pCallbacks->onDeviceUninit=ma_device_uninit__audio4;
pCallbacks->onDeviceStart=ma_device_start__audio4;
pCallbacks->onDeviceStop=ma_device_stop__audio4;
pCallbacks->onDeviceRead=ma_device_read__audio4;
pCallbacks->onDeviceWrite=ma_device_write__audio4;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#ifdef MA_HAS_OSS
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#ifndef SNDCTL_DSP_HALT
#define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
#endif
#define MA_OSS_DEFAULT_DEVICE_NAME "/dev/dsp"
static int ma_open_temp_device__oss()
{
int fd = open("/dev/mixer", O_RDONLY, 0);
if (fd>=0) {
Mr fd;
}
Mr-1;
}
static Me ma_context_open_device__oss(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_share_mode shareMode,int*pfd)
{
const char*deviceName;
int flags;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pfd !=NULL);
(Mv)Mc;
*pfd=-1;
if (deviceType==ma_device_type_duplex) {
Mr MA_INVALID_ARGS;
}
deviceName=MA_OSS_DEFAULT_DEVICE_NAME;
if (pDeviceID !=NULL) {
deviceName=pDeviceID->oss;
}
flags=(deviceType==Mt)?O_WRONLY:O_RDONLY;
if (shareMode==ma_share_mode_exclusive) {
flags|=O_EXCL;
}
*pfd=open(deviceName,flags,0);
if (*pfd==-1) {
Mr ma_result_from_errno(errno);
}
Mr Ms;
}
static Me ma_context_enumerate_devices__oss(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
int fd;
oss_sysinfo si;
int Mf;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
fd=ma_open_temp_device__oss();
if (fd==-1) {
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.");
Mr MA_NO_BACKEND;
}
Mf=ioctl(fd,SNDCTL_SYSINFO,&si);
if (Mf !=-1) {
int iAudioDevice;
for (iAudioDevice=0; iAudioDevice<si.numaudios;++iAudioDevice) {
oss_audioinfo ai;
ai.dev=iAudioDevice;
Mf=ioctl(fd,SNDCTL_AUDIOINFO,&ai);
if (Mf !=-1) {
if (ai.devnode[0] !='\0') {
 ma_device_info deviceInfo;
 ma_bool32 isTerminating=MA_FALSE;
 MA_ZERO_OBJECT(&deviceInfo);
 ma_strncpy_s(deviceInfo.id.oss,sizeof(deviceInfo.id.oss),ai.devnode,(size_t)-1);
 if (ai.handle[0] !='\0') {
 ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),ai.handle,(size_t)-1);
 } else {
 ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),ai.name,(size_t)-1);
 }
 if (!isTerminating&&(ai.caps&PCM_CAP_OUTPUT) !=0) {
 isTerminating=!callback(Mc,Mt,&deviceInfo,pUserData);
 }
 if (!isTerminating&&(ai.caps&PCM_CAP_INPUT) !=0) {
 isTerminating=!callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
 }
 if (isTerminating) {
 break;
 }
}
}
}
} else {
close(fd);
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.");
Mr MA_NO_BACKEND;
}
close(fd);
Mr Ms;
}
static Mv ma_context_add_native_data_format__oss(ma_context*Mc,oss_audioinfo*pAudioInfo,ma_format format,ma_device_info*pDeviceInfo)
{
unsigned int minChannels;
unsigned int maxChannels;
unsigned int iRate;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pAudioInfo !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
minChannels=ma_clamp(pAudioInfo->min_channels,MA_MIN_CHANNELS,MA_MAX_CHANNELS);
maxChannels=ma_clamp(pAudioInfo->max_channels,MA_MIN_CHANNELS,MA_MAX_CHANNELS);
if (pAudioInfo->nrates>0) {
for (iRate=0; iRate<pAudioInfo->nrates; iRate+=1) {
unsigned int rate=pAudioInfo->rates[iRate];
if (minChannels==MA_MIN_CHANNELS&&maxChannels==MA_MAX_CHANNELS) {
ma_device_info_add_native_data_format(pDeviceInfo,format,0,rate,0);
} else {
unsigned int iChannel;
for (iChannel=minChannels; iChannel<=maxChannels; iChannel+=1) {
 ma_device_info_add_native_data_format(pDeviceInfo,format,iChannel,rate,0);
}
}
}
} else {
for (iRate=0; iRate<ma_countof(g_maStandardSampleRatePriorities); iRate+=1) {
M3 standardRate=g_maStandardSampleRatePriorities[iRate];
if (standardRate>=(M3)pAudioInfo->min_rate&&standardRate<=(M3)pAudioInfo->max_rate) {
if (minChannels==MA_MIN_CHANNELS&&maxChannels==MA_MAX_CHANNELS) {
 ma_device_info_add_native_data_format(pDeviceInfo,format,0,standardRate,0);
} else {
 unsigned int iChannel;
 for (iChannel=minChannels; iChannel<=maxChannels; iChannel+=1) {
 ma_device_info_add_native_data_format(pDeviceInfo,format,iChannel,standardRate,0);
 }
}
}
}
}
}
static Me ma_context_get_device_info__oss(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
ma_bool32 foundDevice;
int fdTemp;
oss_sysinfo si;
int Mf;
MA_ASSERT(Mc !=NULL);
if (pDeviceID==NULL) {
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
Mr Ms;
}
foundDevice=MA_FALSE;
fdTemp=ma_open_temp_device__oss();
if (fdTemp==-1) {
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.");
Mr MA_NO_BACKEND;
}
Mf=ioctl(fdTemp,SNDCTL_SYSINFO,&si);
if (Mf !=-1) {
int iAudioDevice;
for (iAudioDevice=0; iAudioDevice<si.numaudios;++iAudioDevice) {
oss_audioinfo ai;
ai.dev=iAudioDevice;
Mf=ioctl(fdTemp,SNDCTL_AUDIOINFO,&ai);
if (Mf !=-1) {
if (ma_strcmp(ai.devnode,pDeviceID->oss)==0) {
 if ((deviceType==Mt&&((ai.caps&PCM_CAP_OUTPUT) !=0))||
 (deviceType==ma_device_type_capture&&((ai.caps&PCM_CAP_INPUT) !=0))) {
 unsigned int formatMask;
 ma_strncpy_s(pDeviceInfo->id.oss,sizeof(pDeviceInfo->id.oss),ai.devnode,(size_t)-1);
 if (ai.handle[0] !='\0') {
 ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),ai.handle,(size_t)-1);
 } else {
 ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),ai.name,(size_t)-1);
 }
 pDeviceInfo->nativeDataFormatCount=0;
 if (deviceType==Mt) {
 formatMask=ai.oformats;
 } else {
 formatMask=ai.iformats;
 }
 if (((formatMask&AFMT_S16_LE) !=0&&ma_is_little_endian())||(AFMT_S16_BE&&ma_is_big_endian())) {
 ma_context_add_native_data_format__oss(Mc,&ai,ma_format_s16,pDeviceInfo);
 }
 if (((formatMask&AFMT_S32_LE) !=0&&ma_is_little_endian())||(AFMT_S32_BE&&ma_is_big_endian())) {
 ma_context_add_native_data_format__oss(Mc,&ai,ma_format_s32,pDeviceInfo);
 }
 if ((formatMask&AFMT_U8) !=0) {
 ma_context_add_native_data_format__oss(Mc,&ai,ma_format_u8,pDeviceInfo);
 }
 foundDevice=MA_TRUE;
 break;
 }
}
}
}
} else {
close(fdTemp);
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.");
Mr MA_NO_BACKEND;
}
close(fdTemp);
if (!foundDevice) {
Mr MA_NO_DEVICE;
}
Mr Ms;
}
static Me ma_device_uninit__oss(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
close(Md->oss.fdCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
close(Md->oss.fdPlayback);
}
Mr Ms;
}
static int ma_format_to_oss(ma_format format)
{
int ossFormat=AFMT_U8;
switch (format) {
case ma_format_s16:ossFormat=(ma_is_little_endian())?AFMT_S16_LE:AFMT_S16_BE; break;
case ma_format_s24:ossFormat=(ma_is_little_endian())?AFMT_S32_LE:AFMT_S32_BE; break;
case ma_format_s32:ossFormat=(ma_is_little_endian())?AFMT_S32_LE:AFMT_S32_BE; break;
case ma_format_f32:ossFormat=(ma_is_little_endian())?AFMT_S16_LE:AFMT_S16_BE; break;
case ma_format_u8:
default:ossFormat=AFMT_U8; break;
}
Mr ossFormat;
}
static ma_format ma_format_from_oss(int ossFormat)
{
if (ossFormat==AFMT_U8) {
Mr ma_format_u8;
} else {
if (ma_is_little_endian()) {
switch (ossFormat) {
case AFMT_S16_LE:Mr ma_format_s16;
case AFMT_S32_LE:Mr ma_format_s32;
default:Mr ma_format_unknown;
}
} else {
switch (ossFormat) {
case AFMT_S16_BE:Mr ma_format_s16;
case AFMT_S32_BE:Mr ma_format_s32;
default:Mr ma_format_unknown;
}
}
}
Mr ma_format_unknown;
}
static Me ma_device_init_fd__oss(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*pDescriptor,ma_device_type deviceType)
{
Me Mf;
int ossResult;
int fd;
const ma_device_id*pDeviceID=NULL;
ma_share_mode shareMode;
int ossFormat;
int ossChannels;
int ossSampleRate;
int ossFragment;
MA_ASSERT(Md !=NULL);
MA_ASSERT(Mo !=NULL);
MA_ASSERT(deviceType !=ma_device_type_duplex);
pDeviceID=pDescriptor->pDeviceID;
shareMode=pDescriptor->shareMode;
ossFormat=ma_format_to_oss((pDescriptor->format !=ma_format_unknown)?pDescriptor->format:ma_format_s16);
ossChannels=(int)(pDescriptor->Mh>0)?pDescriptor->Mh:MA_DEFAULT_CHANNELS;
ossSampleRate=(int)(pDescriptor->sampleRate>0)?pDescriptor->sampleRate:MA_DEFAULT_SAMPLE_RATE;
Mf=ma_context_open_device__oss(Md->Mc,deviceType,pDeviceID,shareMode,&fd);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
Mr Mf;
}
ossResult=ioctl(fd,SNDCTL_DSP_SETFMT,&ossFormat);
if (ossResult==-1) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.");
Mr ma_result_from_errno(errno);
}
ossResult=ioctl(fd,SNDCTL_DSP_CHANNELS,&ossChannels);
if (ossResult==-1) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.");
Mr ma_result_from_errno(errno);
}
ossResult=ioctl(fd,SNDCTL_DSP_SPEED,&ossSampleRate);
if (ossResult==-1) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.");
Mr ma_result_from_errno(errno);
}
{
M3 periodSizeInFrames;
M3 periodSizeInBytes;
M3 ossFragmentSizePower;
periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,(M3)ossSampleRate,Mo->performanceProfile);
periodSizeInBytes=ma_round_to_power_of_2(periodSizeInFrames*ma_get_bytes_per_frame(ma_format_from_oss(ossFormat),ossChannels));
if (periodSizeInBytes<16) {
periodSizeInBytes=16;
}
ossFragmentSizePower=4;
periodSizeInBytes>>=4;
while (periodSizeInBytes>>=1) {
ossFragmentSizePower+=1;
}
ossFragment=(int)((Mo->periods<<16)|ossFragmentSizePower);
ossResult=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&ossFragment);
if (ossResult==-1) {
close(fd);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.");
Mr ma_result_from_errno(errno);
}
}
if (deviceType==ma_device_type_capture) {
Md->oss.fdCapture=fd;
} else {
Md->oss.fdPlayback=fd;
}
pDescriptor->format=ma_format_from_oss(ossFormat);
pDescriptor->Mh=ossChannels;
pDescriptor->sampleRate=ossSampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_sound4,pDescriptor->channelMap,ma_countof(pDescriptor->channelMap),pDescriptor->Mh);
pDescriptor->periodCount=(M3)(ossFragment>>16);
pDescriptor->periodSizeInFrames=(M3)(1<<(ossFragment&0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format,pDescriptor->Mh);
if (pDescriptor->format==ma_format_unknown) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.");
Mr MA_FORMAT_NOT_SUPPORTED;
}
Mr Ms;
}
static Me ma_device_init__oss(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(Mo !=NULL);
MA_ZERO_OBJECT(&Md->oss);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_fd__oss(Md,Mo,pDescriptorCapture,ma_device_type_capture);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
Mr Mf;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Me Mf=ma_device_init_fd__oss(Md,Mo,Mp,Mt);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_start__oss(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
(Mv)Md;
Mr Ms;
}
static Me ma_device_stop__oss(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
(Mv)Md;
Mr Ms;
}
static Me ma_device_write__oss(ma_device*Md,const Mv*pPCMFrames,M3 frameCount,M3*pFramesWritten)
{
int resultOSS;
M3 deviceState;
if (pFramesWritten !=NULL) {
*pFramesWritten=0;
}
deviceState=ma_device_get_state(Md);
if (deviceState !=ma_device_state_started&&deviceState !=ma_device_state_starting) {
Mr Ms;
}
resultOSS=write(Md->oss.fdPlayback,pPCMFrames,frameCount*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
if (resultOSS<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.");
Mr ma_result_from_errno(errno);
}
if (pFramesWritten !=NULL) {
*pFramesWritten=(M3)resultOSS / ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
}
Mr Ms;
}
static Me ma_device_read__oss(ma_device*Md,Mv*pPCMFrames,M3 frameCount,M3*pFramesRead)
{
int resultOSS;
M3 deviceState;
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
deviceState=ma_device_get_state(Md);
if (deviceState !=ma_device_state_started&&deviceState !=ma_device_state_starting) {
Mr Ms;
}
resultOSS=read(Md->oss.fdCapture,pPCMFrames,frameCount*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels));
if (resultOSS<0) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.");
Mr ma_result_from_errno(errno);
}
if (pFramesRead !=NULL) {
*pFramesRead=(M3)resultOSS / ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
}
Mr Ms;
}
static Me ma_context_uninit__oss(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_oss);
(Mv)Mc;
Mr Ms;
}
static Me ma_context_init__oss(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
int fd;
int ossVersion;
int Mf;
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
fd=ma_open_temp_device__oss();
if (fd==-1) {
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.");
Mr MA_NO_BACKEND;
}
ossVersion=0;
Mf=ioctl(fd,OSS_GETVERSION,&ossVersion);
if (Mf==-1) {
close(fd);
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.");
Mr MA_NO_BACKEND;
}
close(fd);
Mc->oss.versionMajor=((ossVersion&0xFF0000)>>16);
Mc->oss.versionMinor=((ossVersion&0x00FF00)>>8);
pCallbacks->onContextInit=ma_context_init__oss;
pCallbacks->onContextUninit=ma_context_uninit__oss;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__oss;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__oss;
pCallbacks->onDeviceInit=ma_device_init__oss;
pCallbacks->onDeviceUninit=ma_device_uninit__oss;
pCallbacks->onDeviceStart=ma_device_start__oss;
pCallbacks->onDeviceStop=ma_device_stop__oss;
pCallbacks->onDeviceRead=ma_device_read__oss;
pCallbacks->onDeviceWrite=ma_device_write__oss;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#ifdef MA_HAS_AAUDIO
#ifdef MA_NO_RUNTIME_LINKING
#include <AAudio/AAudio.h>
#endif
typedef int32_t ma_aaudio_result_t;
typedef int32_t ma_aaudio_direction_t;
typedef int32_t ma_aaudio_sharing_mode_t;
typedef int32_t ma_aaudio_format_t;
typedef int32_t ma_aaudio_stream_state_t;
typedef int32_t ma_aaudio_performance_mode_t;
typedef int32_t ma_aaudio_usage_t;
typedef int32_t ma_aaudio_content_type_t;
typedef int32_t ma_aaudio_input_preset_t;
typedef int32_t ma_aaudio_allowed_capture_policy_t;
typedef int32_t ma_aaudio_data_callback_result_t;
typedef struct ma_AAudioStreamBuilder_t*ma_AAudioStreamBuilder;
typedef struct ma_AAudioStream_t*ma_AAudioStream;
#define MA_AAUDIO_UNSPECIFIED 0
#define MA_AAUDIO_OK 0
#define MA_AAUDIO_DIRECTION_OUTPUT 0
#define MA_AAUDIO_DIRECTION_INPUT 1
#define MA_AAUDIO_SHARING_MODE_EXCLUSIVE 0
#define MA_AAUDIO_SHARING_MODE_SHARED 1
#define MA_AAUDIO_FORMAT_PCM_I16 1
#define MA_AAUDIO_FORMAT_PCM_FLOAT 2
#define MA_AAUDIO_STREAM_STATE_UNINITIALIZED 0
#define MA_AAUDIO_STREAM_STATE_UNKNOWN 1
#define MA_AAUDIO_STREAM_STATE_OPEN 2
#define MA_AAUDIO_STREAM_STATE_STARTING 3
#define MA_AAUDIO_STREAM_STATE_STARTED 4
#define MA_AAUDIO_STREAM_STATE_PAUSING 5
#define MA_AAUDIO_STREAM_STATE_PAUSED 6
#define MA_AAUDIO_STREAM_STATE_FLUSHING 7
#define MA_AAUDIO_STREAM_STATE_FLUSHED 8
#define MA_AAUDIO_STREAM_STATE_STOPPING 9
#define MA_AAUDIO_STREAM_STATE_STOPPED 10
#define MA_AAUDIO_STREAM_STATE_CLOSING 11
#define MA_AAUDIO_STREAM_STATE_CLOSED 12
#define MA_AAUDIO_STREAM_STATE_DISCONNECTED 13
#define MA_AAUDIO_PERFORMANCE_MODE_NONE 10
#define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING 11
#define MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY 12
#define MA_AAUDIO_USAGE_MEDIA 1
#define MA_AAUDIO_USAGE_VOICE_COMMUNICATION 2
#define MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING 3
#define MA_AAUDIO_USAGE_ALARM 4
#define MA_AAUDIO_USAGE_NOTIFICATION 5
#define MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE 6
#define MA_AAUDIO_USAGE_NOTIFICATION_EVENT 10
#define MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY 11
#define MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE 12
#define MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION 13
#define MA_AAUDIO_USAGE_GAME 14
#define MA_AAUDIO_USAGE_ASSISTANT 16
#define MA_AAUDIO_SYSTEM_USAGE_EMERGENCY 1000
#define MA_AAUDIO_SYSTEM_USAGE_SAFETY 1001
#define MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS 1002
#define MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT 1003
#define MA_AAUDIO_CONTENT_TYPE_SPEECH 1
#define MA_AAUDIO_CONTENT_TYPE_MUSIC 2
#define MA_AAUDIO_CONTENT_TYPE_MOVIE 3
#define MA_AAUDIO_CONTENT_TYPE_SONIFICATION 4
#define MA_AAUDIO_INPUT_PRESET_GENERIC 1
#define MA_AAUDIO_INPUT_PRESET_CAMCORDER 5
#define MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION 6
#define MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION 7
#define MA_AAUDIO_INPUT_PRESET_UNPROCESSED 9
#define MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE 10
#define MA_AAUDIO_ALLOW_CAPTURE_BY_ALL 1
#define MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM 2
#define MA_AAUDIO_ALLOW_CAPTURE_BY_NONE 3
#define MA_AAUDIO_CALLBACK_RESULT_CONTINUE 0
#define MA_AAUDIO_CALLBACK_RESULT_STOP 1
typedef ma_aaudio_data_callback_result_t (*ma_AAudioStream_dataCallback) (ma_AAudioStream*pStream,Mv*pUserData,Mv*pAudioData,int32_t numFrames);
typedef Mv (*ma_AAudioStream_errorCallback)(ma_AAudioStream*pStream,Mv*pUserData,ma_aaudio_result_t error);
typedef ma_aaudio_result_t (*MA_PFN_AAudio_createStreamBuilder) (ma_AAudioStreamBuilder**ppBuilder);
typedef ma_aaudio_result_t (*MA_PFN_AAudioStreamBuilder_delete) (ma_AAudioStreamBuilder*pBuilder);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setDeviceId) (ma_AAudioStreamBuilder*pBuilder,int32_t deviceId);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setDirection) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_direction_t direction);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setSharingMode) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_sharing_mode_t sharingMode);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setFormat) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_format_t format);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setChannelCount) (ma_AAudioStreamBuilder*pBuilder,int32_t channelCount);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setSampleRate) (ma_AAudioStreamBuilder*pBuilder,int32_t sampleRate);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder*pBuilder,int32_t numFrames);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder*pBuilder,int32_t numFrames);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setDataCallback) (ma_AAudioStreamBuilder*pBuilder,ma_AAudioStream_dataCallback callback,Mv*pUserData);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setErrorCallback) (ma_AAudioStreamBuilder*pBuilder,ma_AAudioStream_errorCallback callback,Mv*pUserData);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setPerformanceMode) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_performance_mode_t mode);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setUsage) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_usage_t contentType);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setContentType) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_content_type_t contentType);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setInputPreset) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_input_preset_t inputPreset);
typedef Mv (*MA_PFN_AAudioStreamBuilder_setAllowedCapturePolicy) (ma_AAudioStreamBuilder*pBuilder,ma_aaudio_allowed_capture_policy_t policy);
typedef ma_aaudio_result_t (*MA_PFN_AAudioStreamBuilder_openStream) (ma_AAudioStreamBuilder*pBuilder,ma_AAudioStream**ppStream);
typedef ma_aaudio_result_t (*MA_PFN_AAudioStream_close) (ma_AAudioStream*pStream);
typedef ma_aaudio_stream_state_t (*MA_PFN_AAudioStream_getState) (ma_AAudioStream*pStream);
typedef ma_aaudio_result_t (*MA_PFN_AAudioStream_waitForStateChange) (ma_AAudioStream*pStream,ma_aaudio_stream_state_t inputState,ma_aaudio_stream_state_t*pNextState,int64_t timeoutInNanoseconds);
typedef ma_aaudio_format_t (*MA_PFN_AAudioStream_getFormat) (ma_AAudioStream*pStream);
typedef int32_t (*MA_PFN_AAudioStream_getChannelCount) (ma_AAudioStream*pStream);
typedef int32_t (*MA_PFN_AAudioStream_getSampleRate) (ma_AAudioStream*pStream);
typedef int32_t (*MA_PFN_AAudioStream_getBufferCapacityInFrames) (ma_AAudioStream*pStream);
typedef int32_t (*MA_PFN_AAudioStream_getFramesPerDataCallback) (ma_AAudioStream*pStream);
typedef int32_t (*MA_PFN_AAudioStream_getFramesPerBurst) (ma_AAudioStream*pStream);
typedef ma_aaudio_result_t (*MA_PFN_AAudioStream_requestStart) (ma_AAudioStream*pStream);
typedef ma_aaudio_result_t (*MA_PFN_AAudioStream_requestStop) (ma_AAudioStream*pStream);
static Me ma_result_from_aaudio(ma_aaudio_result_t resultAA)
{
switch (resultAA)
{
case MA_AAUDIO_OK:Mr Ms;
default:break;
}
Mr MA_ERROR;
}
static ma_aaudio_usage_t ma_to_usage__aaudio(ma_aaudio_usage usage)
{
switch (usage) {
case ma_aaudio_usage_media:Mr MA_AAUDIO_USAGE_MEDIA;
case ma_aaudio_usage_voice_communication:Mr MA_AAUDIO_USAGE_VOICE_COMMUNICATION;
case ma_aaudio_usage_voice_communication_signalling:Mr MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
case ma_aaudio_usage_alarm:Mr MA_AAUDIO_USAGE_ALARM;
case ma_aaudio_usage_notification:Mr MA_AAUDIO_USAGE_NOTIFICATION;
case ma_aaudio_usage_notification_ringtone:Mr MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE;
case ma_aaudio_usage_notification_event:Mr MA_AAUDIO_USAGE_NOTIFICATION_EVENT;
case ma_aaudio_usage_assistance_accessibility:Mr MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
case ma_aaudio_usage_assistance_navigation_guidance:Mr MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
case ma_aaudio_usage_assistance_sonification:Mr MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION;
case ma_aaudio_usage_game:Mr MA_AAUDIO_USAGE_GAME;
case ma_aaudio_usage_assitant:Mr MA_AAUDIO_USAGE_ASSISTANT;
case ma_aaudio_usage_emergency:Mr MA_AAUDIO_SYSTEM_USAGE_EMERGENCY;
case ma_aaudio_usage_safety:Mr MA_AAUDIO_SYSTEM_USAGE_SAFETY;
case ma_aaudio_usage_vehicle_status:Mr MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS;
case ma_aaudio_usage_announcement:Mr MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT;
default:break;
}
Mr MA_AAUDIO_USAGE_MEDIA;
}
static ma_aaudio_content_type_t ma_to_content_type__aaudio(ma_aaudio_content_type contentType)
{
switch (contentType) {
case ma_aaudio_content_type_speech:Mr MA_AAUDIO_CONTENT_TYPE_SPEECH;
case ma_aaudio_content_type_music:Mr MA_AAUDIO_CONTENT_TYPE_MUSIC;
case ma_aaudio_content_type_movie:Mr MA_AAUDIO_CONTENT_TYPE_MOVIE;
case ma_aaudio_content_type_sonification:Mr MA_AAUDIO_CONTENT_TYPE_SONIFICATION;
default:break;
}
Mr MA_AAUDIO_CONTENT_TYPE_SPEECH;
}
static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_preset inputPreset)
{
switch (inputPreset) {
case ma_aaudio_input_preset_generic:Mr MA_AAUDIO_INPUT_PRESET_GENERIC;
case ma_aaudio_input_preset_camcorder:Mr MA_AAUDIO_INPUT_PRESET_CAMCORDER;
case ma_aaudio_input_preset_voice_recognition:Mr MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
case ma_aaudio_input_preset_voice_communication:Mr MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION;
case ma_aaudio_input_preset_unprocessed:Mr MA_AAUDIO_INPUT_PRESET_UNPROCESSED;
case ma_aaudio_input_preset_voice_performance:Mr MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE;
default:break;
}
Mr MA_AAUDIO_INPUT_PRESET_GENERIC;
}
static ma_aaudio_allowed_capture_policy_t ma_to_allowed_capture_policy__aaudio(ma_aaudio_allowed_capture_policy allowedCapturePolicy)
{
switch (allowedCapturePolicy) {
case ma_aaudio_allow_capture_by_all:Mr MA_AAUDIO_ALLOW_CAPTURE_BY_ALL;
case ma_aaudio_allow_capture_by_system:Mr MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM;
case ma_aaudio_allow_capture_by_none:Mr MA_AAUDIO_ALLOW_CAPTURE_BY_NONE;
default:break;
}
Mr MA_AAUDIO_ALLOW_CAPTURE_BY_ALL;
}
static Mv ma_stream_error_callback__aaudio(ma_AAudioStream*pStream,Mv*pUserData,ma_aaudio_result_t error)
{
Me Mf;
ma_job job;
ma_device*Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
(Mv)error;
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)Md->Mc->aaudio.AAudioStream_getState)(pStream));
job=ma_job_init(MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE);
job.data.device.aaudio.reroute.Md=Md;
if (pStream==Md->aaudio.pStreamCapture) {
job.data.device.aaudio.reroute.deviceType=ma_device_type_capture;
}
else {
job.data.device.aaudio.reroute.deviceType=Mt;
}
Mf=ma_device_job_thread_post(&Md->Mc->aaudio.jobThread,&job);
if (Mf !=Ms) {
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[AAudio] Device Disconnected. Failed to post job for rerouting.\n");
Mr;
}
}
static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream*pStream,Mv*pUserData,Mv*pAudioData,int32_t frameCount)
{
ma_device*Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
if (frameCount>0) {
ma_device_handle_backend_data_callback(Md,NULL,pAudioData,(M3)frameCount);
}
(Mv)pStream;
Mr MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
}
static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream*pStream,Mv*pUserData,Mv*pAudioData,int32_t frameCount)
{
ma_device*Md=(ma_device*)pUserData;
MA_ASSERT(Md !=NULL);
if (frameCount>0) {
ma_device_handle_backend_data_callback(Md,pAudioData,NULL,(M3)frameCount);
}
(Mv)pStream;
Mr MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
}
static Me ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context*Mc,const ma_device_id*pDeviceID,ma_device_type deviceType,ma_share_mode shareMode,const ma_device_descriptor*pDescriptor,const ma_device_config*Mo,ma_device*Md,ma_AAudioStreamBuilder**ppBuilder)
{
ma_AAudioStreamBuilder*pBuilder;
ma_aaudio_result_t resultAA;
*ppBuilder=NULL;
resultAA=((MA_PFN_AAudio_createStreamBuilder)Mc->aaudio.AAudio_createStreamBuilder)(&pBuilder);
if (resultAA !=MA_AAUDIO_OK) {
Mr ma_result_from_aaudio(resultAA);
}
if (pDeviceID !=NULL) {
((MA_PFN_AAudioStreamBuilder_setDeviceId)Mc->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder,pDeviceID->aaudio);
}
((MA_PFN_AAudioStreamBuilder_setDirection)Mc->aaudio.AAudioStreamBuilder_setDirection)(pBuilder,(deviceType==Mt)?MA_AAUDIO_DIRECTION_OUTPUT:MA_AAUDIO_DIRECTION_INPUT);
((MA_PFN_AAudioStreamBuilder_setSharingMode)Mc->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder,(shareMode==ma_share_mode_shared)?MA_AAUDIO_SHARING_MODE_SHARED:MA_AAUDIO_SHARING_MODE_EXCLUSIVE);
if (pDescriptor !=NULL) {
MA_ASSERT(Mo !=NULL);
if (pDescriptor->sampleRate !=0) {
((MA_PFN_AAudioStreamBuilder_setSampleRate)Mc->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder,pDescriptor->sampleRate);
}
if (pDescriptor->Mh !=0) {
((MA_PFN_AAudioStreamBuilder_setChannelCount)Mc->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder,pDescriptor->Mh);
}
if (pDescriptor->format !=ma_format_unknown) {
((MA_PFN_AAudioStreamBuilder_setFormat)Mc->aaudio.AAudioStreamBuilder_setFormat)(pBuilder,(pDescriptor->format==ma_format_s16)?MA_AAUDIO_FORMAT_PCM_I16:MA_AAUDIO_FORMAT_PCM_FLOAT);
}
if ((!Mo->aaudio.enableCompatibilityWorkarounds||ma_android_sdk_version()>30)&&Mo->aaudio.allowSetBufferCapacity) {
M3 bufferCapacityInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor,pDescriptor->sampleRate,Mo->performanceProfile)*pDescriptor->periodCount;
((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)Mc->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder,bufferCapacityInFrames);
((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)Mc->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder,bufferCapacityInFrames / pDescriptor->periodCount);
}
if (deviceType==ma_device_type_capture) {
if (Mo->aaudio.inputPreset !=ma_aaudio_input_preset_default&&Mc->aaudio.AAudioStreamBuilder_setInputPreset !=NULL) {
((MA_PFN_AAudioStreamBuilder_setInputPreset)Mc->aaudio.AAudioStreamBuilder_setInputPreset)(pBuilder,ma_to_input_preset__aaudio(Mo->aaudio.inputPreset));
}
((MA_PFN_AAudioStreamBuilder_setDataCallback)Mc->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder,ma_stream_data_callback_capture__aaudio,(Mv*)Md);
} else {
if (Mo->aaudio.usage !=ma_aaudio_usage_default&&Mc->aaudio.AAudioStreamBuilder_setUsage !=NULL) {
((MA_PFN_AAudioStreamBuilder_setUsage)Mc->aaudio.AAudioStreamBuilder_setUsage)(pBuilder,ma_to_usage__aaudio(Mo->aaudio.usage));
}
if (Mo->aaudio.contentType !=ma_aaudio_content_type_default&&Mc->aaudio.AAudioStreamBuilder_setContentType !=NULL) {
((MA_PFN_AAudioStreamBuilder_setContentType)Mc->aaudio.AAudioStreamBuilder_setContentType)(pBuilder,ma_to_content_type__aaudio(Mo->aaudio.contentType));
}
if (Mo->aaudio.allowedCapturePolicy !=ma_aaudio_allow_capture_default&&Mc->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy !=NULL) {
((MA_PFN_AAudioStreamBuilder_setAllowedCapturePolicy)Mc->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy)(pBuilder,ma_to_allowed_capture_policy__aaudio(Mo->aaudio.allowedCapturePolicy));
}
((MA_PFN_AAudioStreamBuilder_setDataCallback)Mc->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder,ma_stream_data_callback_playback__aaudio,(Mv*)Md);
}
((MA_PFN_AAudioStreamBuilder_setPerformanceMode)Mc->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder,(Mo->performanceProfile==ma_performance_profile_low_latency)?MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:MA_AAUDIO_PERFORMANCE_MODE_NONE);
if (Md !=NULL) {
((MA_PFN_AAudioStreamBuilder_setErrorCallback)Mc->aaudio.AAudioStreamBuilder_setErrorCallback)(pBuilder,ma_stream_error_callback__aaudio,(Mv*)Md);
}
}
*ppBuilder=pBuilder;
Mr Ms;
}
static Me ma_open_stream_and_close_builder__aaudio(ma_context*Mc,ma_AAudioStreamBuilder*pBuilder,ma_AAudioStream**ppStream)
{
Me Mf;
Mf=ma_result_from_aaudio(((MA_PFN_AAudioStreamBuilder_openStream)Mc->aaudio.AAudioStreamBuilder_openStream)(pBuilder,ppStream));
((MA_PFN_AAudioStreamBuilder_delete)Mc->aaudio.AAudioStreamBuilder_delete)(pBuilder);
Mr Mf;
}
static Me ma_open_stream_basic__aaudio(ma_context*Mc,const ma_device_id*pDeviceID,ma_device_type deviceType,ma_share_mode shareMode,ma_AAudioStream**ppStream)
{
Me Mf;
ma_AAudioStreamBuilder*pBuilder;
*ppStream=NULL;
Mf=ma_create_and_configure_AAudioStreamBuilder__aaudio(Mc,pDeviceID,deviceType,shareMode,NULL,NULL,NULL,&pBuilder);
if (Mf !=Ms) {
Mr Mf;
}
((MA_PFN_AAudioStreamBuilder_setPerformanceMode)Mc->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder,MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
Mr ma_open_stream_and_close_builder__aaudio(Mc,pBuilder,ppStream);
}
static Me ma_open_stream__aaudio(ma_device*Md,const ma_device_config*Mo,ma_device_type deviceType,const ma_device_descriptor*pDescriptor,ma_AAudioStream**ppStream)
{
Me Mf;
ma_AAudioStreamBuilder*pBuilder;
MA_ASSERT(Md !=NULL);
MA_ASSERT(pDescriptor !=NULL);
MA_ASSERT(deviceType !=ma_device_type_duplex);
*ppStream=NULL;
Mf=ma_create_and_configure_AAudioStreamBuilder__aaudio(Md->Mc,pDescriptor->pDeviceID,deviceType,pDescriptor->shareMode,pDescriptor,Mo,Md,&pBuilder);
if (Mf !=Ms) {
Mr Mf;
}
Mr ma_open_stream_and_close_builder__aaudio(Md->Mc,pBuilder,ppStream);
}
static Me ma_close_stream__aaudio(ma_context*Mc,ma_AAudioStream*pStream)
{
if (pStream==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_result_from_aaudio(((MA_PFN_AAudioStream_close)Mc->aaudio.AAudioStream_close)(pStream));
}
static ma_bool32 ma_has_default_device__aaudio(ma_context*Mc,ma_device_type deviceType)
{
ma_AAudioStream*pStream;
Me Mf=ma_open_stream_basic__aaudio(Mc,NULL,deviceType,ma_share_mode_shared,&pStream);
if (Mf !=Ms) {
Mr MA_FALSE;
}
ma_close_stream__aaudio(Mc,pStream);
Mr MA_TRUE;
}
static Me ma_wait_for_simple_state_transition__aaudio(ma_context*Mc,ma_AAudioStream*pStream,ma_aaudio_stream_state_t oldState,ma_aaudio_stream_state_t newState)
{
ma_aaudio_stream_state_t actualNewState;
ma_aaudio_result_t resultAA=((MA_PFN_AAudioStream_waitForStateChange)Mc->aaudio.AAudioStream_waitForStateChange)(pStream,oldState,&actualNewState,5000000000);
if (resultAA !=MA_AAUDIO_OK) {
Mr ma_result_from_aaudio(resultAA);
}
if (newState !=actualNewState) {
Mr MA_ERROR;
}
Mr Ms;
}
static Me ma_context_enumerate_devices__aaudio(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_bool32 cbResult=MA_TRUE;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.aaudio=MA_AAUDIO_UNSPECIFIED;
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
if (ma_has_default_device__aaudio(Mc,Mt)) {
cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
}
}
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.aaudio=MA_AAUDIO_UNSPECIFIED;
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
if (ma_has_default_device__aaudio(Mc,ma_device_type_capture)) {
cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
}
Mr Ms;
}
static Mv ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(ma_context*Mc,ma_AAudioStream*pStream,ma_format format,M3 flags,ma_device_info*pDeviceInfo)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pStream !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=format;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=((MA_PFN_AAudioStream_getChannelCount)Mc->aaudio.AAudioStream_getChannelCount)(pStream);
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=((MA_PFN_AAudioStream_getSampleRate)Mc->aaudio.AAudioStream_getSampleRate)(pStream);
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=flags;
pDeviceInfo->nativeDataFormatCount+=1;
}
static Mv ma_context_add_native_data_format_from_AAudioStream__aaudio(ma_context*Mc,ma_AAudioStream*pStream,M3 flags,ma_device_info*pDeviceInfo)
{
ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(Mc,pStream,ma_format_f32,flags,pDeviceInfo);
ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(Mc,pStream,ma_format_s16,flags,pDeviceInfo);
}
static Me ma_context_get_device_info__aaudio(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
ma_AAudioStream*pStream;
Me Mf;
MA_ASSERT(Mc !=NULL);
if (pDeviceID !=NULL) {
pDeviceInfo->id.aaudio=pDeviceID->aaudio;
} else {
pDeviceInfo->id.aaudio=MA_AAUDIO_UNSPECIFIED;
}
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
pDeviceInfo->nativeDataFormatCount=0;
Mf=ma_open_stream_basic__aaudio(Mc,pDeviceID,deviceType,ma_share_mode_shared,&pStream);
if (Mf !=Ms) {
Mr Mf;
}
ma_context_add_native_data_format_from_AAudioStream__aaudio(Mc,pStream,0,pDeviceInfo);
ma_close_stream__aaudio(Mc,pStream);
pStream=NULL;
Mr Ms;
}
static Me ma_close_streams__aaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
ma_close_stream__aaudio(Md->Mc,(ma_AAudioStream*)Md->aaudio.pStreamCapture);
Md->aaudio.pStreamCapture=NULL;
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_close_stream__aaudio(Md->Mc,(ma_AAudioStream*)Md->aaudio.pStreamPlayback);
Md->aaudio.pStreamPlayback=NULL;
}
Mr Ms;
}
static Me ma_device_uninit__aaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
ma_mutex_lock(&Md->aaudio.rerouteLock);
{
ma_close_streams__aaudio(Md);
}
ma_mutex_unlock(&Md->aaudio.rerouteLock);
ma_mutex_uninit(&Md->aaudio.rerouteLock);
Mr Ms;
}
static Me ma_device_init_by_type__aaudio(ma_device*Md,const ma_device_config*Mo,ma_device_type deviceType,ma_device_descriptor*pDescriptor,ma_AAudioStream**ppStream)
{
Me Mf;
int32_t bufferCapacityInFrames;
int32_t framesPerDataCallback;
ma_AAudioStream*pStream;
MA_ASSERT(Md !=NULL);
MA_ASSERT(Mo !=NULL);
MA_ASSERT(pDescriptor !=NULL);
*ppStream=NULL;
Mf=ma_open_stream__aaudio(Md,Mo,deviceType,pDescriptor,&pStream);
if (Mf !=Ms) {
Mr Mf;
}
pDescriptor->format=(((MA_PFN_AAudioStream_getFormat)Md->Mc->aaudio.AAudioStream_getFormat)(pStream)==MA_AAUDIO_FORMAT_PCM_I16)?ma_format_s16:ma_format_f32;
pDescriptor->Mh=((MA_PFN_AAudioStream_getChannelCount)Md->Mc->aaudio.AAudioStream_getChannelCount)(pStream);
pDescriptor->sampleRate=((MA_PFN_AAudioStream_getSampleRate)Md->Mc->aaudio.AAudioStream_getSampleRate)(pStream);
if (pDescriptor->Mh<=MA_MAX_CHANNELS) {
ma_channel_map_init_standard(ma_standard_channel_map_default,pDescriptor->channelMap,ma_countof(pDescriptor->channelMap),pDescriptor->Mh);
} else {
ma_channel_map_init_blank(pDescriptor->channelMap,MA_MAX_CHANNELS);
}
bufferCapacityInFrames=((MA_PFN_AAudioStream_getBufferCapacityInFrames)Md->Mc->aaudio.AAudioStream_getBufferCapacityInFrames)(pStream);
framesPerDataCallback=((MA_PFN_AAudioStream_getFramesPerDataCallback)Md->Mc->aaudio.AAudioStream_getFramesPerDataCallback)(pStream);
if (framesPerDataCallback>0) {
pDescriptor->periodSizeInFrames=framesPerDataCallback;
pDescriptor->periodCount=bufferCapacityInFrames / framesPerDataCallback;
} else {
pDescriptor->periodSizeInFrames=bufferCapacityInFrames;
pDescriptor->periodCount=1;
}
*ppStream=pStream;
Mr Ms;
}
static Me ma_device_init_streams__aaudio(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
MA_ASSERT(Md !=NULL);
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
Md->aaudio.usage=Mo->aaudio.usage;
Md->aaudio.contentType=Mo->aaudio.contentType;
Md->aaudio.inputPreset=Mo->aaudio.inputPreset;
Md->aaudio.allowedCapturePolicy=Mo->aaudio.allowedCapturePolicy;
Md->aaudio.noAutoStartAfterReroute=Mo->aaudio.noAutoStartAfterReroute;
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
Mf=ma_device_init_by_type__aaudio(Md,Mo,ma_device_type_capture,pDescriptorCapture,(ma_AAudioStream**)&Md->aaudio.pStreamCapture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Mf=ma_device_init_by_type__aaudio(Md,Mo,Mt,Mp,(ma_AAudioStream**)&Md->aaudio.pStreamPlayback);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_init__aaudio(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
MA_ASSERT(Md !=NULL);
Mf=ma_device_init_streams__aaudio(Md,Mo,Mp,pDescriptorCapture);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_mutex_init(&Md->aaudio.rerouteLock);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static Me ma_device_start_stream__aaudio(ma_device*Md,ma_AAudioStream*pStream)
{
ma_aaudio_result_t resultAA;
ma_aaudio_stream_state_t currentState;
MA_ASSERT(Md !=NULL);
if (pStream==NULL) {
Mr MA_INVALID_ARGS;
}
resultAA=((MA_PFN_AAudioStream_requestStart)Md->Mc->aaudio.AAudioStream_requestStart)(pStream);
if (resultAA !=MA_AAUDIO_OK) {
Mr ma_result_from_aaudio(resultAA);
}
currentState=((MA_PFN_AAudioStream_getState)Md->Mc->aaudio.AAudioStream_getState)(pStream);
if (currentState !=MA_AAUDIO_STREAM_STATE_STARTED) {
Me Mf;
if (currentState !=MA_AAUDIO_STREAM_STATE_STARTING) {
Mr MA_ERROR;
}
Mf=ma_wait_for_simple_state_transition__aaudio(Md->Mc,pStream,currentState,MA_AAUDIO_STREAM_STATE_STARTED);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_stop_stream__aaudio(ma_device*Md,ma_AAudioStream*pStream)
{
ma_aaudio_result_t resultAA;
ma_aaudio_stream_state_t currentState;
MA_ASSERT(Md !=NULL);
if (pStream==NULL) {
Mr MA_INVALID_ARGS;
}
currentState=((MA_PFN_AAudioStream_getState)Md->Mc->aaudio.AAudioStream_getState)(pStream);
if (currentState==MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
Mr Ms;
}
resultAA=((MA_PFN_AAudioStream_requestStop)Md->Mc->aaudio.AAudioStream_requestStop)(pStream);
if (resultAA !=MA_AAUDIO_OK) {
Mr ma_result_from_aaudio(resultAA);
}
currentState=((MA_PFN_AAudioStream_getState)Md->Mc->aaudio.AAudioStream_getState)(pStream);
if (currentState !=MA_AAUDIO_STREAM_STATE_STOPPED) {
Me Mf;
if (currentState !=MA_AAUDIO_STREAM_STATE_STOPPING) {
Mr MA_ERROR;
}
Mf=ma_wait_for_simple_state_transition__aaudio(Md->Mc,pStream,currentState,MA_AAUDIO_STREAM_STATE_STOPPED);
if (Mf !=Ms) {
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_start__aaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
Me Mf=ma_device_start_stream__aaudio(Md,(ma_AAudioStream*)Md->aaudio.pStreamCapture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
Me Mf=ma_device_start_stream__aaudio(Md,(ma_AAudioStream*)Md->aaudio.pStreamPlayback);
if (Mf !=Ms) {
if (Md->type==ma_device_type_duplex) {
ma_device_stop_stream__aaudio(Md,(ma_AAudioStream*)Md->aaudio.pStreamCapture);
}
Mr Mf;
}
}
Mr Ms;
}
static Me ma_device_stop__aaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
Me Mf=ma_device_stop_stream__aaudio(Md,(ma_AAudioStream*)Md->aaudio.pStreamCapture);
if (Mf !=Ms) {
Mr Mf;
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
Me Mf=ma_device_stop_stream__aaudio(Md,(ma_AAudioStream*)Md->aaudio.pStreamPlayback);
if (Mf !=Ms) {
Mr Mf;
}
}
ma_device__on_notification_stopped(Md);
Mr Ms;
}
static Me ma_device_reinit__aaudio(ma_device*Md,ma_device_type deviceType)
{
Me Mf;
int32_t retries=0;
MA_ASSERT(Md !=NULL);
ma_mutex_lock(&Md->aaudio.rerouteLock);
{
error_disconnected:
ma_close_streams__aaudio(Md);
ma_device_config deviceConfig;
ma_device_descriptor descriptorPlayback;
ma_device_descriptor descriptorCapture;
deviceConfig=ma_device_config_init(deviceType);
deviceConfig.playback.pDeviceID=NULL;
deviceConfig.playback.shareMode=Md->playback.shareMode;
deviceConfig.playback.format=Md->playback.format;
deviceConfig.playback.Mh=Md->playback.Mh;
deviceConfig.capture.pDeviceID=NULL;
deviceConfig.capture.shareMode=Md->capture.shareMode;
deviceConfig.capture.format=Md->capture.format;
deviceConfig.capture.Mh=Md->capture.Mh;
deviceConfig.sampleRate=Md->sampleRate;
deviceConfig.aaudio.usage=Md->aaudio.usage;
deviceConfig.aaudio.contentType=Md->aaudio.contentType;
deviceConfig.aaudio.inputPreset=Md->aaudio.inputPreset;
deviceConfig.aaudio.allowedCapturePolicy=Md->aaudio.allowedCapturePolicy;
deviceConfig.aaudio.noAutoStartAfterReroute=Md->aaudio.noAutoStartAfterReroute;
deviceConfig.periods=1;
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
deviceConfig.periodSizeInFrames=Md->playback.internalPeriodSizeInFrames;
} else {
deviceConfig.periodSizeInFrames=Md->capture.internalPeriodSizeInFrames;
}
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_duplex||deviceType==ma_device_type_loopback) {
descriptorCapture.pDeviceID=deviceConfig.capture.pDeviceID;
descriptorCapture.shareMode=deviceConfig.capture.shareMode;
descriptorCapture.format=deviceConfig.capture.format;
descriptorCapture.Mh=deviceConfig.capture.Mh;
descriptorCapture.sampleRate=deviceConfig.sampleRate;
descriptorCapture.periodSizeInFrames=deviceConfig.periodSizeInFrames;
descriptorCapture.periodCount=deviceConfig.periods;
}
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
descriptorPlayback.pDeviceID=deviceConfig.playback.pDeviceID;
descriptorPlayback.shareMode=deviceConfig.playback.shareMode;
descriptorPlayback.format=deviceConfig.playback.format;
descriptorPlayback.Mh=deviceConfig.playback.Mh;
descriptorPlayback.sampleRate=deviceConfig.sampleRate;
descriptorPlayback.periodSizeInFrames=deviceConfig.periodSizeInFrames;
descriptorPlayback.periodCount=deviceConfig.periods;
}
Mf=ma_device_init_streams__aaudio(Md,&deviceConfig,&descriptorPlayback,&descriptorCapture);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change.");
goto done;
}
Mf=ma_device_post_init(Md,deviceType,&descriptorPlayback,&descriptorCapture);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change.");
ma_close_streams__aaudio(Md);
goto done;
}
ma_device__on_notification_rerouted(Md);
if (ma_device_get_state(Md)==ma_device_state_started) {
if (Md->aaudio.noAutoStartAfterReroute==MA_FALSE) {
Mf=ma_device_start__aaudio(Md);
if (Mf !=Ms) {
 retries+=1;
 if (retries<=3) {
 ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries);
 goto error_disconnected;
 }
 ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change.");
 goto done;
}
} else {
ma_device_stop(Md);
}
}

Mf=Ms;
}
done:
ma_mutex_unlock(&Md->aaudio.rerouteLock);
Mr Mf;
}
static Me ma_device_get_info__aaudio(ma_device*Md,ma_device_type type,ma_device_info*pDeviceInfo)
{
ma_AAudioStream*pStream=NULL;
MA_ASSERT(Md !=NULL);
MA_ASSERT(type !=ma_device_type_duplex);
MA_ASSERT(pDeviceInfo !=NULL);
if (type==ma_device_type_capture) {
pStream=(ma_AAudioStream*)Md->aaudio.pStreamCapture;
pDeviceInfo->id.aaudio=Md->capture.id.aaudio;
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
if (type==Mt) {
pStream=(ma_AAudioStream*)Md->aaudio.pStreamPlayback;
pDeviceInfo->id.aaudio=Md->playback.id.aaudio;
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
}
if (pStream==NULL) {
Mr MA_INVALID_OPERATION;
}
pDeviceInfo->nativeDataFormatCount=0;
ma_context_add_native_data_format_from_AAudioStream__aaudio(Md->Mc,pStream,0,pDeviceInfo);
Mr Ms;
}
static Me ma_context_uninit__aaudio(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_aaudio);
ma_device_job_thread_uninit(&Mc->aaudio.jobThread,&Mc->allocationCallbacks);
ma_dlclose(ma_context_get_log(Mc),Mc->aaudio.hAAudio);
Mc->aaudio.hAAudio=NULL;
Mr Ms;
}
static Me ma_context_init__aaudio(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
#if !defined(MA_NO_RUNTIME_LINKING)
size_t i;
const char*libNames[]={
"libaaudio.so"
};
for (i=0; i<ma_countof(libNames);++i) {
Mc->aaudio.hAAudio=ma_dlopen(ma_context_get_log(Mc),libNames[i]);
if (Mc->aaudio.hAAudio !=NULL) {
break;
}
}
if (Mc->aaudio.hAAudio==NULL) {
Mr MA_FAILED_TO_INIT_BACKEND;
}
Mc->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudio_createStreamBuilder");
Mc->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_delete");
Mc->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId");
Mc->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setDirection");
Mc->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode");
Mc->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setFormat");
Mc->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount");
Mc->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate");
Mc->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames");
Mc->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback");
Mc->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback");
Mc->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback");
Mc->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode");
Mc->aaudio.AAudioStreamBuilder_setUsage = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setUsage");
Mc->aaudio.AAudioStreamBuilder_setContentType = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setContentType");
Mc->aaudio.AAudioStreamBuilder_setInputPreset = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setInputPreset");
Mc->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_setAllowedCapturePolicy");
Mc->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStreamBuilder_openStream");
Mc->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_close");
Mc->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getState");
Mc->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_waitForStateChange");
Mc->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getFormat");
Mc->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getChannelCount");
Mc->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getSampleRate");
Mc->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames");
Mc->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback");
Mc->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_getFramesPerBurst");
Mc->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_requestStart");
Mc->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->aaudio.hAAudio, "AAudioStream_requestStop");
#else
Mc->aaudio.AAudio_createStreamBuilder=(ma_proc)AAudio_createStreamBuilder;
Mc->aaudio.AAudioStreamBuilder_delete=(ma_proc)AAudioStreamBuilder_delete;
Mc->aaudio.AAudioStreamBuilder_setDeviceId=(ma_proc)AAudioStreamBuilder_setDeviceId;
Mc->aaudio.AAudioStreamBuilder_setDirection=(ma_proc)AAudioStreamBuilder_setDirection;
Mc->aaudio.AAudioStreamBuilder_setSharingMode=(ma_proc)AAudioStreamBuilder_setSharingMode;
Mc->aaudio.AAudioStreamBuilder_setFormat=(ma_proc)AAudioStreamBuilder_setFormat;
Mc->aaudio.AAudioStreamBuilder_setChannelCount=(ma_proc)AAudioStreamBuilder_setChannelCount;
Mc->aaudio.AAudioStreamBuilder_setSampleRate=(ma_proc)AAudioStreamBuilder_setSampleRate;
Mc->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames=(ma_proc)AAudioStreamBuilder_setBufferCapacityInFrames;
Mc->aaudio.AAudioStreamBuilder_setFramesPerDataCallback=(ma_proc)AAudioStreamBuilder_setFramesPerDataCallback;
Mc->aaudio.AAudioStreamBuilder_setDataCallback=(ma_proc)AAudioStreamBuilder_setDataCallback;
Mc->aaudio.AAudioStreamBuilder_setErrorCallback=(ma_proc)AAudioStreamBuilder_setErrorCallback;
Mc->aaudio.AAudioStreamBuilder_setPerformanceMode=(ma_proc)AAudioStreamBuilder_setPerformanceMode;
Mc->aaudio.AAudioStreamBuilder_setUsage=(ma_proc)AAudioStreamBuilder_setUsage;
Mc->aaudio.AAudioStreamBuilder_setContentType=(ma_proc)AAudioStreamBuilder_setContentType;
Mc->aaudio.AAudioStreamBuilder_setInputPreset=(ma_proc)AAudioStreamBuilder_setInputPreset;
#if defined(__ANDROID_API__)&&__ANDROID_API__>=29
Mc->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy=(ma_proc)AAudioStreamBuilder_setAllowedCapturePolicy;
#endif
Mc->aaudio.AAudioStreamBuilder_openStream=(ma_proc)AAudioStreamBuilder_openStream;
Mc->aaudio.AAudioStream_close=(ma_proc)AAudioStream_close;
Mc->aaudio.AAudioStream_getState=(ma_proc)AAudioStream_getState;
Mc->aaudio.AAudioStream_waitForStateChange=(ma_proc)AAudioStream_waitForStateChange;
Mc->aaudio.AAudioStream_getFormat=(ma_proc)AAudioStream_getFormat;
Mc->aaudio.AAudioStream_getChannelCount=(ma_proc)AAudioStream_getChannelCount;
Mc->aaudio.AAudioStream_getSampleRate=(ma_proc)AAudioStream_getSampleRate;
Mc->aaudio.AAudioStream_getBufferCapacityInFrames=(ma_proc)AAudioStream_getBufferCapacityInFrames;
Mc->aaudio.AAudioStream_getFramesPerDataCallback=(ma_proc)AAudioStream_getFramesPerDataCallback;
Mc->aaudio.AAudioStream_getFramesPerBurst=(ma_proc)AAudioStream_getFramesPerBurst;
Mc->aaudio.AAudioStream_requestStart=(ma_proc)AAudioStream_requestStart;
Mc->aaudio.AAudioStream_requestStop=(ma_proc)AAudioStream_requestStop;
#endif
pCallbacks->onContextInit=ma_context_init__aaudio;
pCallbacks->onContextUninit=ma_context_uninit__aaudio;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__aaudio;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__aaudio;
pCallbacks->onDeviceInit=ma_device_init__aaudio;
pCallbacks->onDeviceUninit=ma_device_uninit__aaudio;
pCallbacks->onDeviceStart=ma_device_start__aaudio;
pCallbacks->onDeviceStop=ma_device_stop__aaudio;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=NULL;
pCallbacks->onDeviceGetInfo=ma_device_get_info__aaudio;
{
Me Mf;
ma_device_job_thread_config jobThreadConfig;
jobThreadConfig=ma_device_job_thread_config_init();
Mf=ma_device_job_thread_init(&jobThreadConfig,&Mc->allocationCallbacks,&Mc->aaudio.jobThread);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->aaudio.hAAudio);
Mc->aaudio.hAAudio=NULL;
Mr Mf;
}
}
(Mv)Mo;
Mr Ms;
}
static Me ma_job_process__device__aaudio_reroute(ma_job*pJob)
{
Me Mf;
ma_device*Md;
MA_ASSERT(pJob !=NULL);
Md=(ma_device*)pJob->data.device.aaudio.reroute.Md;
MA_ASSERT(Md !=NULL);
Mf=ma_device_reinit__aaudio(Md,(ma_device_type)pJob->data.device.aaudio.reroute.deviceType);
if (Mf !=Ms) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure.");
ma_device_stop(Md);
Mr Mf;
}
Mr Ms;
}
#else
static Me ma_job_process__device__aaudio_reroute(ma_job*pJob)
{
Mr ma_job_process__noop(pJob);
}
#endif
#ifdef MA_HAS_OPENSL
#include <SLES/OpenSLES.h>
#ifdef MA_ANDROID
#include <SLES/OpenSLES_Android.h>
#endif
typedef SLresult (SLAPIENTRY*ma_slCreateEngine_proc)(SLObjectItf*pEngine,SLuint32 numOptions,SLEngineOption*pEngineOptions,SLuint32 numInterfaces,SLInterfaceID*pInterfaceIds,SLboolean*pInterfaceRequired);
static SLObjectItf g_maEngineObjectSL=NULL;
static SLEngineItf g_maEngineSL=NULL;
static M3 g_maOpenSLInitCounter=0;
static ma_spinlock g_maOpenSLSpinlock=0;
#define MA_OPENSL_OBJ(p) (*((SLObjectItf)(p)))
#define MA_OPENSL_OUTPUTMIX(p) (*((SLOutputMixItf)(p)))
#define MA_OPENSL_PLAY(p) (*((SLPlayItf)(p)))
#define MA_OPENSL_RECORD(p) (*((SLRecordItf)(p)))
#ifdef MA_ANDROID
#define MA_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p)))
#else
#define MA_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p)))
#endif
static Me ma_result_from_OpenSL(SLuint32 Mf)
{
switch (Mf)
{
case SL_RESULT_SUCCESS:Mr Ms;
case SL_RESULT_PRECONDITIONS_VIOLATED:Mr MA_ERROR;
case SL_RESULT_PARAMETER_INVALID:Mr MA_INVALID_ARGS;
case SL_RESULT_MEMORY_FAILURE:Mr MA_OUT_OF_MEMORY;
case SL_RESULT_RESOURCE_ERROR:Mr MA_INVALID_DATA;
case SL_RESULT_RESOURCE_LOST:Mr MA_ERROR;
case SL_RESULT_IO_ERROR:Mr MA_IO_ERROR;
case SL_RESULT_BUFFER_INSUFFICIENT:Mr MA_NO_SPACE;
case SL_RESULT_CONTENT_CORRUPTED:Mr MA_INVALID_DATA;
case SL_RESULT_CONTENT_UNSUPPORTED:Mr MA_FORMAT_NOT_SUPPORTED;
case SL_RESULT_CONTENT_NOT_FOUND:Mr MA_ERROR;
case SL_RESULT_PERMISSION_DENIED:Mr MA_ACCESS_DENIED;
case SL_RESULT_FEATURE_UNSUPPORTED:Mr MA_NOT_IMPLEMENTED;
case SL_RESULT_INTERNAL_ERROR:Mr MA_ERROR;
case SL_RESULT_UNKNOWN_ERROR:Mr MA_ERROR;
case SL_RESULT_OPERATION_ABORTED:Mr MA_ERROR;
case SL_RESULT_CONTROL_LOST:Mr MA_ERROR;
default:Mr MA_ERROR;
}
}
static ma_uint8 ma_channel_id_to_ma__opensl(SLuint32 id)
{
switch (id)
{
case SL_SPEAKER_FRONT_LEFT:Mr MA_CHANNEL_FRONT_LEFT;
case SL_SPEAKER_FRONT_RIGHT:Mr MA_CHANNEL_FRONT_RIGHT;
case SL_SPEAKER_FRONT_CENTER:Mr MA_CHANNEL_FRONT_CENTER;
case SL_SPEAKER_LOW_FREQUENCY:Mr MA_CHANNEL_LFE;
case SL_SPEAKER_BACK_LEFT:Mr MA_CHANNEL_BACK_LEFT;
case SL_SPEAKER_BACK_RIGHT:Mr MA_CHANNEL_BACK_RIGHT;
case SL_SPEAKER_FRONT_LEFT_OF_CENTER:Mr MA_CHANNEL_FRONT_LEFT_CENTER;
case SL_SPEAKER_FRONT_RIGHT_OF_CENTER:Mr MA_CHANNEL_FRONT_RIGHT_CENTER;
case SL_SPEAKER_BACK_CENTER:Mr MA_CHANNEL_BACK_CENTER;
case SL_SPEAKER_SIDE_LEFT:Mr MA_CHANNEL_SIDE_LEFT;
case SL_SPEAKER_SIDE_RIGHT:Mr MA_CHANNEL_SIDE_RIGHT;
case SL_SPEAKER_TOP_CENTER:Mr MA_CHANNEL_TOP_CENTER;
case SL_SPEAKER_TOP_FRONT_LEFT:Mr MA_CHANNEL_TOP_FRONT_LEFT;
case SL_SPEAKER_TOP_FRONT_CENTER:Mr MA_CHANNEL_TOP_FRONT_CENTER;
case SL_SPEAKER_TOP_FRONT_RIGHT:Mr MA_CHANNEL_TOP_FRONT_RIGHT;
case SL_SPEAKER_TOP_BACK_LEFT:Mr MA_CHANNEL_TOP_BACK_LEFT;
case SL_SPEAKER_TOP_BACK_CENTER:Mr MA_CHANNEL_TOP_BACK_CENTER;
case SL_SPEAKER_TOP_BACK_RIGHT:Mr MA_CHANNEL_TOP_BACK_RIGHT;
default:Mr 0;
}
}
static SLuint32 ma_channel_id_to_opensl(ma_uint8 id)
{
switch (id)
{
case MA_CHANNEL_MONO:Mr SL_SPEAKER_FRONT_CENTER;
case MA_CHANNEL_FRONT_LEFT:Mr SL_SPEAKER_FRONT_LEFT;
case MA_CHANNEL_FRONT_RIGHT:Mr SL_SPEAKER_FRONT_RIGHT;
case MA_CHANNEL_FRONT_CENTER:Mr SL_SPEAKER_FRONT_CENTER;
case MA_CHANNEL_LFE:Mr SL_SPEAKER_LOW_FREQUENCY;
case MA_CHANNEL_BACK_LEFT:Mr SL_SPEAKER_BACK_LEFT;
case MA_CHANNEL_BACK_RIGHT:Mr SL_SPEAKER_BACK_RIGHT;
case MA_CHANNEL_FRONT_LEFT_CENTER:Mr SL_SPEAKER_FRONT_LEFT_OF_CENTER;
case MA_CHANNEL_FRONT_RIGHT_CENTER:Mr SL_SPEAKER_FRONT_RIGHT_OF_CENTER;
case MA_CHANNEL_BACK_CENTER:Mr SL_SPEAKER_BACK_CENTER;
case MA_CHANNEL_SIDE_LEFT:Mr SL_SPEAKER_SIDE_LEFT;
case MA_CHANNEL_SIDE_RIGHT:Mr SL_SPEAKER_SIDE_RIGHT;
case MA_CHANNEL_TOP_CENTER:Mr SL_SPEAKER_TOP_CENTER;
case MA_CHANNEL_TOP_FRONT_LEFT:Mr SL_SPEAKER_TOP_FRONT_LEFT;
case MA_CHANNEL_TOP_FRONT_CENTER:Mr SL_SPEAKER_TOP_FRONT_CENTER;
case MA_CHANNEL_TOP_FRONT_RIGHT:Mr SL_SPEAKER_TOP_FRONT_RIGHT;
case MA_CHANNEL_TOP_BACK_LEFT:Mr SL_SPEAKER_TOP_BACK_LEFT;
case MA_CHANNEL_TOP_BACK_CENTER:Mr SL_SPEAKER_TOP_BACK_CENTER;
case MA_CHANNEL_TOP_BACK_RIGHT:Mr SL_SPEAKER_TOP_BACK_RIGHT;
default:Mr 0;
}
}
static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel*pChannelMap,M3 Mh)
{
SLuint32 channelMask=0;
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
channelMask|=ma_channel_id_to_opensl(pChannelMap[iChannel]);
}
Mr channelMask;
}
static Mv ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask,M3 Mh,ma_channel*pChannelMap)
{
if (Mh==1&&channelMask==0) {
pChannelMap[0]=MA_CHANNEL_MONO;
} else if (Mh==2&&channelMask==0) {
pChannelMap[0]=MA_CHANNEL_FRONT_LEFT;
pChannelMap[1]=MA_CHANNEL_FRONT_RIGHT;
} else {
if (Mh==1&&(channelMask&SL_SPEAKER_FRONT_CENTER) !=0) {
pChannelMap[0]=MA_CHANNEL_MONO;
} else {
M3 iChannel=0;
M3 iBit;
for (iBit=0; iBit<32&&iChannel<Mh;++iBit) {
SLuint32 bitValue=(channelMask&(1UL<<iBit));
if (bitValue !=0) {
 pChannelMap[iChannel]=ma_channel_id_to_ma__opensl(bitValue);
 iChannel+=1;
}
}
}
}
}
static SLuint32 ma_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec)
{
if (samplesPerSec<=SL_SAMPLINGRATE_8) {
Mr SL_SAMPLINGRATE_8;
}
if (samplesPerSec<=SL_SAMPLINGRATE_11_025) {
Mr SL_SAMPLINGRATE_11_025;
}
if (samplesPerSec<=SL_SAMPLINGRATE_12) {
Mr SL_SAMPLINGRATE_12;
}
if (samplesPerSec<=SL_SAMPLINGRATE_16) {
Mr SL_SAMPLINGRATE_16;
}
if (samplesPerSec<=SL_SAMPLINGRATE_22_05) {
Mr SL_SAMPLINGRATE_22_05;
}
if (samplesPerSec<=SL_SAMPLINGRATE_24) {
Mr SL_SAMPLINGRATE_24;
}
if (samplesPerSec<=SL_SAMPLINGRATE_32) {
Mr SL_SAMPLINGRATE_32;
}
if (samplesPerSec<=SL_SAMPLINGRATE_44_1) {
Mr SL_SAMPLINGRATE_44_1;
}
if (samplesPerSec<=SL_SAMPLINGRATE_48) {
Mr SL_SAMPLINGRATE_48;
}
#ifndef MA_ANDROID
if (samplesPerSec<=SL_SAMPLINGRATE_64) {
Mr SL_SAMPLINGRATE_64;
}
if (samplesPerSec<=SL_SAMPLINGRATE_88_2) {
Mr SL_SAMPLINGRATE_88_2;
}
if (samplesPerSec<=SL_SAMPLINGRATE_96) {
Mr SL_SAMPLINGRATE_96;
}
if (samplesPerSec<=SL_SAMPLINGRATE_192) {
Mr SL_SAMPLINGRATE_192;
}
#endif
Mr SL_SAMPLINGRATE_16;
}
static SLint32 ma_to_stream_type__opensl(ma_opensl_stream_type streamType)
{
switch (streamType) {
case ma_opensl_stream_type_voice:Mr SL_ANDROID_STREAM_VOICE;
case ma_opensl_stream_type_system:Mr SL_ANDROID_STREAM_SYSTEM;
case ma_opensl_stream_type_ring:Mr SL_ANDROID_STREAM_RING;
case ma_opensl_stream_type_media:Mr SL_ANDROID_STREAM_MEDIA;
case ma_opensl_stream_type_alarm:Mr SL_ANDROID_STREAM_ALARM;
case ma_opensl_stream_type_notification:Mr SL_ANDROID_STREAM_NOTIFICATION;
default:break;
}
Mr SL_ANDROID_STREAM_VOICE;
}
static SLint32 ma_to_recording_preset__opensl(ma_opensl_recording_preset recordingPreset)
{
switch (recordingPreset) {
case ma_opensl_recording_preset_generic:Mr SL_ANDROID_RECORDING_PRESET_GENERIC;
case ma_opensl_recording_preset_camcorder:Mr SL_ANDROID_RECORDING_PRESET_CAMCORDER;
case ma_opensl_recording_preset_voice_recognition:Mr SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
case ma_opensl_recording_preset_voice_communication:Mr SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
case ma_opensl_recording_preset_voice_unprocessed:Mr SL_ANDROID_RECORDING_PRESET_UNPROCESSED;
default:break;
}
Mr SL_ANDROID_RECORDING_PRESET_NONE;
}
static Me ma_context_enumerate_devices__opensl(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_bool32 cbResult;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
MA_ASSERT(g_maOpenSLInitCounter>0);
if (g_maOpenSLInitCounter==0) {
Mr MA_INVALID_OPERATION;
}
#if 0&&!defined(MA_ANDROID)
ma_bool32 isTerminated=MA_FALSE;
SLuint32 pDeviceIDs[128];
SLint32 deviceCount=sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]);
SLAudioIODeviceCapabilitiesItf deviceCaps;
SLresult resultSL=(*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL,(SLInterfaceID)Mc->opensl.SL_IID_AUDIOIODEVICECAPABILITIES,&deviceCaps);
if (resultSL !=SL_RESULT_SUCCESS) {
goto return_default_device;
}
if (!isTerminated) {
resultSL=(*deviceCaps)->GetAvailableAudioOutputs(deviceCaps,&deviceCount,pDeviceIDs);
if (resultSL !=SL_RESULT_SUCCESS) {
Mr ma_result_from_OpenSL(resultSL);
}
for (SLint32 iDevice=0; iDevice<deviceCount;++iDevice) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.opensl=pDeviceIDs[iDevice];
SLAudioOutputDescriptor desc;
resultSL=(*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps,deviceInfo.id.opensl,&desc);
if (resultSL==SL_RESULT_SUCCESS) {
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),(const char*)desc.pDeviceName,(size_t)-1);
ma_bool32 cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
if (cbResult==MA_FALSE) {
 isTerminated=MA_TRUE;
 break;
}
}
}
}
if (!isTerminated) {
resultSL=(*deviceCaps)->GetAvailableAudioInputs(deviceCaps,&deviceCount,pDeviceIDs);
if (resultSL !=SL_RESULT_SUCCESS) {
Mr ma_result_from_OpenSL(resultSL);
}
for (SLint32 iDevice=0; iDevice<deviceCount;++iDevice) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.opensl=pDeviceIDs[iDevice];
SLAudioInputDescriptor desc;
resultSL=(*deviceCaps)->QueryAudioInputCapabilities(deviceCaps,deviceInfo.id.opensl,&desc);
if (resultSL==SL_RESULT_SUCCESS) {
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),(const char*)desc.deviceName,(size_t)-1);
ma_bool32 cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
if (cbResult==MA_FALSE) {
 isTerminated=MA_TRUE;
 break;
}
}
}
}
Mr Ms;
#else
goto return_default_device;
#endif
return_default_device:;
cbResult=MA_TRUE;
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.opensl=SL_DEFAULTDEVICEID_AUDIOOUTPUT;
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
}
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.id.opensl=SL_DEFAULTDEVICEID_AUDIOINPUT;
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
Mr Ms;
}
static Mv ma_context_add_data_format_ex__opensl(ma_context*Mc,ma_format format,M3 Mh,M3 sampleRate,ma_device_info*pDeviceInfo)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format=format;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].Mh=Mh;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate=sampleRate;
pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags=0;
pDeviceInfo->nativeDataFormatCount+=1;
}
static Mv ma_context_add_data_format__opensl(ma_context*Mc,ma_format format,ma_device_info*pDeviceInfo)
{
M3 minChannels=1;
M3 maxChannels=2;
M3 minSampleRate=(M3)ma_standard_sample_rate_8000;
M3 maxSampleRate=(M3)ma_standard_sample_rate_48000;
M3 iChannel;
M3 iSampleRate;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(pDeviceInfo !=NULL);
for (iChannel=minChannels; iChannel<maxChannels; iChannel+=1) {
for (iSampleRate=0; iSampleRate<ma_countof(g_maStandardSampleRatePriorities); iSampleRate+=1) {
M3 standardSampleRate=g_maStandardSampleRatePriorities[iSampleRate];
if (standardSampleRate>=minSampleRate&&standardSampleRate<=maxSampleRate) {
ma_context_add_data_format_ex__opensl(Mc,format,iChannel,standardSampleRate,pDeviceInfo);
}
}
}
}
static Me ma_context_get_device_info__opensl(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(g_maOpenSLInitCounter>0);
if (g_maOpenSLInitCounter==0) {
Mr MA_INVALID_OPERATION;
}
#if 0&&!defined(MA_ANDROID)
SLAudioIODeviceCapabilitiesItf deviceCaps;
SLresult resultSL=(*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL,(SLInterfaceID)Mc->opensl.SL_IID_AUDIOIODEVICECAPABILITIES,&deviceCaps);
if (resultSL !=SL_RESULT_SUCCESS) {
goto return_default_device;
}
if (deviceType==Mt) {
SLAudioOutputDescriptor desc;
resultSL=(*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps,pDeviceID->opensl,&desc);
if (resultSL !=SL_RESULT_SUCCESS) {
Mr ma_result_from_OpenSL(resultSL);
}
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),(const char*)desc.pDeviceName,(size_t)-1);
} else {
SLAudioInputDescriptor desc;
resultSL=(*deviceCaps)->QueryAudioInputCapabilities(deviceCaps,pDeviceID->opensl,&desc);
if (resultSL !=SL_RESULT_SUCCESS) {
Mr ma_result_from_OpenSL(resultSL);
}
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),(const char*)desc.deviceName,(size_t)-1);
}
goto return_detailed_info;
#else
goto return_default_device;
#endif
return_default_device:
if (pDeviceID !=NULL) {
if ((deviceType==Mt&&pDeviceID->opensl !=SL_DEFAULTDEVICEID_AUDIOOUTPUT)||
(deviceType==ma_device_type_capture&&pDeviceID->opensl !=SL_DEFAULTDEVICEID_AUDIOINPUT)) {
Mr MA_NO_DEVICE;
}
}
if (deviceType==Mt) {
pDeviceInfo->id.opensl=SL_DEFAULTDEVICEID_AUDIOOUTPUT;
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
pDeviceInfo->id.opensl=SL_DEFAULTDEVICEID_AUDIOINPUT;
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
pDeviceInfo->isDefault=MA_TRUE;
goto return_detailed_info;
return_detailed_info:
pDeviceInfo->nativeDataFormatCount=0;
#if defined(MA_ANDROID)&&__ANDROID_API__>=21
ma_context_add_data_format__opensl(Mc,ma_format_f32,pDeviceInfo);
#endif
ma_context_add_data_format__opensl(Mc,ma_format_s16,pDeviceInfo);
ma_context_add_data_format__opensl(Mc,ma_format_u8,pDeviceInfo);
Mr Ms;
}
#ifdef MA_ANDROID
static Mv ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
size_t periodSizeInBytes;
ma_uint8*pBuffer;
SLresult resultSL;
MA_ASSERT(Md !=NULL);
(Mv)pBufferQueue;
if (ma_device_get_state(Md) !=ma_device_state_started) {
Mr;
}
if (Md->opensl.isDrainingCapture) {
Mr;
}
periodSizeInBytes=Md->capture.internalPeriodSizeInFrames*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
pBuffer=Md->opensl.pBufferCapture+(Md->opensl.currentBufferIndexCapture*periodSizeInBytes);
ma_device_handle_backend_data_callback(Md,NULL,pBuffer,Md->capture.internalPeriodSizeInFrames);
resultSL=MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueueCapture,pBuffer,periodSizeInBytes);
if (resultSL !=SL_RESULT_SUCCESS) {
Mr;
}
Md->opensl.currentBufferIndexCapture=(Md->opensl.currentBufferIndexCapture+1) % Md->capture.internalPeriods;
}
static Mv ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
size_t periodSizeInBytes;
ma_uint8*pBuffer;
SLresult resultSL;
MA_ASSERT(Md !=NULL);
(Mv)pBufferQueue;
if (ma_device_get_state(Md) !=ma_device_state_started) {
Mr;
}
if (Md->opensl.isDrainingPlayback) {
Mr;
}
periodSizeInBytes=Md->playback.internalPeriodSizeInFrames*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
pBuffer=Md->opensl.pBufferPlayback+(Md->opensl.currentBufferIndexPlayback*periodSizeInBytes);
ma_device_handle_backend_data_callback(Md,pBuffer,NULL,Md->playback.internalPeriodSizeInFrames);
resultSL=MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueuePlayback,pBuffer,periodSizeInBytes);
if (resultSL !=SL_RESULT_SUCCESS) {
Mr;
}
Md->opensl.currentBufferIndexPlayback=(Md->opensl.currentBufferIndexPlayback+1) % Md->playback.internalPeriods;
}
#endif
static Me ma_device_uninit__opensl(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
MA_ASSERT(g_maOpenSLInitCounter>0);
if (g_maOpenSLInitCounter==0) {
Mr MA_INVALID_OPERATION;
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
if (Md->opensl.pAudioRecorderObj) {
MA_OPENSL_OBJ(Md->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)Md->opensl.pAudioRecorderObj);
}
ma_free(Md->opensl.pBufferCapture,&Md->Mc->allocationCallbacks);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
if (Md->opensl.pAudioPlayerObj) {
MA_OPENSL_OBJ(Md->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)Md->opensl.pAudioPlayerObj);
}
if (Md->opensl.pOutputMixObj) {
MA_OPENSL_OBJ(Md->opensl.pOutputMixObj)->Destroy((SLObjectItf)Md->opensl.pOutputMixObj);
}
ma_free(Md->opensl.pBufferPlayback,&Md->Mc->allocationCallbacks);
}
Mr Ms;
}
#if defined(MA_ANDROID)&&__ANDROID_API__>=21
typedef SLAndroidDataFormat_PCM_EX ma_SLDataFormat_PCM;
#else
typedef SLDataFormat_PCM ma_SLDataFormat_PCM;
#endif
static Me ma_SLDataFormat_PCM_init__opensl(ma_format format,M3 Mh,M3 sampleRate,const ma_channel*channelMap,ma_SLDataFormat_PCM*pDataFormat)
{
if (format==ma_format_unknown) {
format=MA_DEFAULT_FORMAT;
}
if (Mh==0) {
Mh=MA_DEFAULT_CHANNELS;
}
if (sampleRate==0) {
sampleRate=MA_DEFAULT_SAMPLE_RATE;
}
#if defined(MA_ANDROID)&&__ANDROID_API__>=21
if (format==ma_format_f32) {
pDataFormat->formatType=SL_ANDROID_DATAFORMAT_PCM_EX;
pDataFormat->representation=SL_ANDROID_PCM_REPRESENTATION_FLOAT;
} else {
pDataFormat->formatType=SL_DATAFORMAT_PCM;
}
#else
pDataFormat->formatType=SL_DATAFORMAT_PCM;
#endif
pDataFormat->numChannels=Mh;
((SLDataFormat_PCM*)pDataFormat)->samplesPerSec=ma_round_to_standard_sample_rate__opensl(sampleRate*1000);
pDataFormat->bitsPerSample=ma_get_bytes_per_sample(format)*8;
pDataFormat->channelMask=ma_channel_map_to_channel_mask__opensl(channelMap,Mh);
pDataFormat->endianness=(ma_is_little_endian())?SL_BYTEORDER_LITTLEENDIAN:SL_BYTEORDER_BIGENDIAN;
#ifdef MA_ANDROID
if (pDataFormat->numChannels>2) {
pDataFormat->numChannels=2;
}
#if __ANDROID_API__>=21
if (pDataFormat->formatType==SL_ANDROID_DATAFORMAT_PCM_EX) {
MA_ASSERT(pDataFormat->representation==SL_ANDROID_PCM_REPRESENTATION_FLOAT);
if (pDataFormat->bitsPerSample>32) {
pDataFormat->bitsPerSample=32;
}
} else {
if (pDataFormat->bitsPerSample>16) {
pDataFormat->bitsPerSample=16;
}
}
#else
if (pDataFormat->bitsPerSample>16) {
pDataFormat->bitsPerSample=16;
}
#endif
if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec>SL_SAMPLINGRATE_48) {
((SLDataFormat_PCM*)pDataFormat)->samplesPerSec=SL_SAMPLINGRATE_48;
}
#endif
pDataFormat->containerSize=pDataFormat->bitsPerSample;
Mr Ms;
}
static Me ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM*pDataFormat,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap)
{
ma_bool32 isFloatingPoint=MA_FALSE;
#if defined(MA_ANDROID)&&__ANDROID_API__>=21
if (pDataFormat->formatType==SL_ANDROID_DATAFORMAT_PCM_EX) {
MA_ASSERT(pDataFormat->representation==SL_ANDROID_PCM_REPRESENTATION_FLOAT);
isFloatingPoint=MA_TRUE;
}
#endif
if (isFloatingPoint) {
if (pDataFormat->bitsPerSample==32) {
*pFormat=ma_format_f32;
}
} else {
if (pDataFormat->bitsPerSample==8) {
*pFormat=ma_format_u8;
} else if (pDataFormat->bitsPerSample==16) {
*pFormat=ma_format_s16;
} else if (pDataFormat->bitsPerSample==24) {
*pFormat=ma_format_s24;
} else if (pDataFormat->bitsPerSample==32) {
*pFormat=ma_format_s32;
}
}
*pChannels=pDataFormat->numChannels;
*pSampleRate=((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000;
ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask,ma_min(pDataFormat->numChannels,channelMapCap),pChannelMap);
Mr Ms;
}
static Me ma_device_init__opensl(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
#ifdef MA_ANDROID
SLDataLocator_AndroidSimpleBufferQueue queue;
SLresult resultSL;
size_t bufferSizeInBytes;
SLInterfaceID itfIDs[2];
const SLboolean itfIDsRequired[]={
SL_BOOLEAN_TRUE,SL_BOOLEAN_FALSE
};
#endif
MA_ASSERT(g_maOpenSLInitCounter>0);
if (g_maOpenSLInitCounter==0) {
Mr MA_INVALID_OPERATION;
}
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
#ifdef MA_ANDROID
itfIDs[0]=(SLInterfaceID)Md->Mc->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
itfIDs[1]=(SLInterfaceID)Md->Mc->opensl.SL_IID_ANDROIDCONFIGURATION;
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->shareMode==ma_share_mode_exclusive)) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
MA_ASSERT(Md !=NULL);
MA_ZERO_OBJECT(&Md->opensl);
queue.locatorType=SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
ma_SLDataFormat_PCM pcm;
SLDataLocator_IODevice locatorDevice;
SLDataSource source;
SLDataSink sink;
SLAndroidConfigurationItf pRecorderConfig;
ma_SLDataFormat_PCM_init__opensl(pDescriptorCapture->format,pDescriptorCapture->Mh,pDescriptorCapture->sampleRate,pDescriptorCapture->channelMap,&pcm);
locatorDevice.locatorType=SL_DATALOCATOR_IODEVICE;
locatorDevice.deviceType=SL_IODEVICE_AUDIOINPUT;
locatorDevice.deviceID=SL_DEFAULTDEVICEID_AUDIOINPUT;
locatorDevice.device=NULL;
source.pLocator=&locatorDevice;
source.pFormat=NULL;
queue.numBuffers=pDescriptorCapture->periodCount;
sink.pLocator=&queue;
sink.pFormat=(SLDataFormat_PCM*)&pcm;
resultSL=(*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL,(SLObjectItf*)&Md->opensl.pAudioRecorderObj,&source,&sink,ma_countof(itfIDs),itfIDs,itfIDsRequired);
if (resultSL==SL_RESULT_CONTENT_UNSUPPORTED||resultSL==SL_RESULT_PARAMETER_INVALID) {
pcm.formatType=SL_DATAFORMAT_PCM;
pcm.numChannels=1;
((SLDataFormat_PCM*)&pcm)->samplesPerSec=SL_SAMPLINGRATE_16;
pcm.bitsPerSample=16;
pcm.containerSize=pcm.bitsPerSample;
pcm.channelMask=0;
resultSL=(*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL,(SLObjectItf*)&Md->opensl.pAudioRecorderObj,&source,&sink,ma_countof(itfIDs),itfIDs,itfIDsRequired);
}
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.");
Mr ma_result_from_OpenSL(resultSL);
}
if (Mo->opensl.recordingPreset !=ma_opensl_recording_preset_default) {
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)Md->opensl.pAudioRecorderObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_ANDROIDCONFIGURATION,&pRecorderConfig);
if (resultSL==SL_RESULT_SUCCESS) {
SLint32 recordingPreset=ma_to_recording_preset__opensl(Mo->opensl.recordingPreset);
resultSL=(*pRecorderConfig)->SetConfiguration(pRecorderConfig,SL_ANDROID_KEY_RECORDING_PRESET,&recordingPreset,sizeof(SLint32));
if (resultSL !=SL_RESULT_SUCCESS) {
}
}
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioRecorderObj)->Realize((SLObjectItf)Md->opensl.pAudioRecorderObj,SL_BOOLEAN_FALSE);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)Md->opensl.pAudioRecorderObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_RECORD,&Md->opensl.pAudioRecorder);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)Md->opensl.pAudioRecorderObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE,&Md->opensl.pBufferQueueCapture);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueueCapture,ma_buffer_queue_callback_capture__opensl_android,Md);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.");
Mr ma_result_from_OpenSL(resultSL);
}
ma_deconstruct_SLDataFormat_PCM__opensl(&pcm,&pDescriptorCapture->format,&pDescriptorCapture->Mh,&pDescriptorCapture->sampleRate,pDescriptorCapture->channelMap,ma_countof(pDescriptorCapture->channelMap));
pDescriptorCapture->periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture,pDescriptorCapture->sampleRate,Mo->performanceProfile);
Md->opensl.currentBufferIndexCapture=0;
bufferSizeInBytes=pDescriptorCapture->periodSizeInFrames*ma_get_bytes_per_frame(pDescriptorCapture->format,pDescriptorCapture->Mh)*pDescriptorCapture->periodCount;
Md->opensl.pBufferCapture=(ma_uint8*)ma_calloc(bufferSizeInBytes,&Md->Mc->allocationCallbacks);
if (Md->opensl.pBufferCapture==NULL) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.");
Mr MA_OUT_OF_MEMORY;
}
MA_ZERO_MEMORY(Md->opensl.pBufferCapture,bufferSizeInBytes);
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
ma_SLDataFormat_PCM pcm;
SLDataSource source;
SLDataLocator_OutputMix outmixLocator;
SLDataSink sink;
SLAndroidConfigurationItf pPlayerConfig;
ma_SLDataFormat_PCM_init__opensl(Mp->format,Mp->Mh,Mp->sampleRate,Mp->channelMap,&pcm);
resultSL=(*g_maEngineSL)->CreateOutputMix(g_maEngineSL,(SLObjectItf*)&Md->opensl.pOutputMixObj,0,NULL,NULL);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pOutputMixObj)->Realize((SLObjectItf)Md->opensl.pOutputMixObj,SL_BOOLEAN_FALSE);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pOutputMixObj)->GetInterface((SLObjectItf)Md->opensl.pOutputMixObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_OUTPUTMIX,&Md->opensl.pOutputMix);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.");
Mr ma_result_from_OpenSL(resultSL);
}
if (Mp->pDeviceID !=NULL) {
SLuint32 deviceID_OpenSL=Mp->pDeviceID->opensl;
MA_OPENSL_OUTPUTMIX(Md->opensl.pOutputMix)->ReRoute((SLOutputMixItf)Md->opensl.pOutputMix,1,&deviceID_OpenSL);
}
queue.numBuffers=Mp->periodCount;
source.pLocator=&queue;
source.pFormat=(SLDataFormat_PCM*)&pcm;
outmixLocator.locatorType=SL_DATALOCATOR_OUTPUTMIX;
outmixLocator.outputMix=(SLObjectItf)Md->opensl.pOutputMixObj;
sink.pLocator=&outmixLocator;
sink.pFormat=NULL;
resultSL=(*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL,(SLObjectItf*)&Md->opensl.pAudioPlayerObj,&source,&sink,ma_countof(itfIDs),itfIDs,itfIDsRequired);
if (resultSL==SL_RESULT_CONTENT_UNSUPPORTED||resultSL==SL_RESULT_PARAMETER_INVALID) {
pcm.formatType=SL_DATAFORMAT_PCM;
pcm.numChannels=2;
((SLDataFormat_PCM*)&pcm)->samplesPerSec=SL_SAMPLINGRATE_16;
pcm.bitsPerSample=16;
pcm.containerSize=pcm.bitsPerSample;
pcm.channelMask=SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
resultSL=(*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL,(SLObjectItf*)&Md->opensl.pAudioPlayerObj,&source,&sink,ma_countof(itfIDs),itfIDs,itfIDsRequired);
}
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.");
Mr ma_result_from_OpenSL(resultSL);
}
if (Mo->opensl.streamType !=ma_opensl_stream_type_default) {
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)Md->opensl.pAudioPlayerObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_ANDROIDCONFIGURATION,&pPlayerConfig);
if (resultSL==SL_RESULT_SUCCESS) {
SLint32 streamType=ma_to_stream_type__opensl(Mo->opensl.streamType);
resultSL=(*pPlayerConfig)->SetConfiguration(pPlayerConfig,SL_ANDROID_KEY_STREAM_TYPE,&streamType,sizeof(SLint32));
if (resultSL !=SL_RESULT_SUCCESS) {
}
}
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioPlayerObj)->Realize((SLObjectItf)Md->opensl.pAudioPlayerObj,SL_BOOLEAN_FALSE);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)Md->opensl.pAudioPlayerObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_PLAY,&Md->opensl.pAudioPlayer);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_OBJ(Md->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)Md->opensl.pAudioPlayerObj,(SLInterfaceID)Md->Mc->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE,&Md->opensl.pBufferQueuePlayback);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.");
Mr ma_result_from_OpenSL(resultSL);
}
resultSL=MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueuePlayback,ma_buffer_queue_callback_playback__opensl_android,Md);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.");
Mr ma_result_from_OpenSL(resultSL);
}
ma_deconstruct_SLDataFormat_PCM__opensl(&pcm,&Mp->format,&Mp->Mh,&Mp->sampleRate,Mp->channelMap,ma_countof(Mp->channelMap));
Mp->periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_descriptor(Mp,Mp->sampleRate,Mo->performanceProfile);
Md->opensl.currentBufferIndexPlayback=0;
bufferSizeInBytes=Mp->periodSizeInFrames*ma_get_bytes_per_frame(Mp->format,Mp->Mh)*Mp->periodCount;
Md->opensl.pBufferPlayback=(ma_uint8*)ma_calloc(bufferSizeInBytes,&Md->Mc->allocationCallbacks);
if (Md->opensl.pBufferPlayback==NULL) {
ma_device_uninit__opensl(Md);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.");
Mr MA_OUT_OF_MEMORY;
}
MA_ZERO_MEMORY(Md->opensl.pBufferPlayback,bufferSizeInBytes);
}
Mr Ms;
#else
Mr MA_NO_BACKEND;
#endif
}
static Me ma_device_start__opensl(ma_device*Md)
{
SLresult resultSL;
size_t periodSizeInBytes;
M3 iPeriod;
MA_ASSERT(Md !=NULL);
MA_ASSERT(g_maOpenSLInitCounter>0);
if (g_maOpenSLInitCounter==0) {
Mr MA_INVALID_OPERATION;
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
resultSL=MA_OPENSL_RECORD(Md->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)Md->opensl.pAudioRecorder,SL_RECORDSTATE_RECORDING);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.");
Mr ma_result_from_OpenSL(resultSL);
}
periodSizeInBytes=Md->capture.internalPeriodSizeInFrames*ma_get_bytes_per_frame(Md->capture.internalFormat,Md->capture.internalChannels);
for (iPeriod=0; iPeriod<Md->capture.internalPeriods;++iPeriod) {
resultSL=MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueueCapture,Md->opensl.pBufferCapture+(periodSizeInBytes*iPeriod),periodSizeInBytes);
if (resultSL !=SL_RESULT_SUCCESS) {
MA_OPENSL_RECORD(Md->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)Md->opensl.pAudioRecorder,SL_RECORDSTATE_STOPPED);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.");
Mr ma_result_from_OpenSL(resultSL);
}
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
resultSL=MA_OPENSL_PLAY(Md->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)Md->opensl.pAudioPlayer,SL_PLAYSTATE_PLAYING);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.");
Mr ma_result_from_OpenSL(resultSL);
}
if (Md->type==ma_device_type_duplex) {
MA_ZERO_MEMORY(Md->opensl.pBufferPlayback,Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels));
} else {
ma_device__read_frames_from_client(Md,Md->playback.internalPeriodSizeInFrames*Md->playback.internalPeriods,Md->opensl.pBufferPlayback);
}
periodSizeInBytes=Md->playback.internalPeriodSizeInFrames*ma_get_bytes_per_frame(Md->playback.internalFormat,Md->playback.internalChannels);
for (iPeriod=0; iPeriod<Md->playback.internalPeriods;++iPeriod) {
resultSL=MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueuePlayback,Md->opensl.pBufferPlayback+(periodSizeInBytes*iPeriod),periodSizeInBytes);
if (resultSL !=SL_RESULT_SUCCESS) {
MA_OPENSL_PLAY(Md->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)Md->opensl.pAudioPlayer,SL_PLAYSTATE_STOPPED);
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.");
Mr ma_result_from_OpenSL(resultSL);
}
}
}
Mr Ms;
}
static Me ma_device_drain__opensl(ma_device*Md,ma_device_type deviceType)
{
SLAndroidSimpleBufferQueueItf pBufferQueue;
MA_ASSERT(deviceType==ma_device_type_capture||deviceType==Mt);
if (Md->type==ma_device_type_capture) {
pBufferQueue=(SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueueCapture;
Md->opensl.isDrainingCapture=MA_TRUE;
} else {
pBufferQueue=(SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueuePlayback;
Md->opensl.isDrainingPlayback=MA_TRUE;
}
for (;;) {
SLAndroidSimpleBufferQueueState state;
MA_OPENSL_BUFFERQUEUE(pBufferQueue)->GetState(pBufferQueue,&state);
if (state.count==0) {
break;
}
ma_sleep(10);
}
if (Md->type==ma_device_type_capture) {
Md->opensl.isDrainingCapture=MA_FALSE;
} else {
Md->opensl.isDrainingPlayback=MA_FALSE;
}
Mr Ms;
}
static Me ma_device_stop__opensl(ma_device*Md)
{
SLresult resultSL;
MA_ASSERT(Md !=NULL);
MA_ASSERT(g_maOpenSLInitCounter>0);
if (g_maOpenSLInitCounter==0) {
Mr MA_INVALID_OPERATION;
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex) {
ma_device_drain__opensl(Md,ma_device_type_capture);
resultSL=MA_OPENSL_RECORD(Md->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)Md->opensl.pAudioRecorder,SL_RECORDSTATE_STOPPED);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.");
Mr ma_result_from_OpenSL(resultSL);
}
MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueueCapture);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_device_drain__opensl(Md,Mt);
resultSL=MA_OPENSL_PLAY(Md->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)Md->opensl.pAudioPlayer,SL_PLAYSTATE_STOPPED);
if (resultSL !=SL_RESULT_SUCCESS) {
ma_log_post(ma_device_get_log(Md), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.");
Mr ma_result_from_OpenSL(resultSL);
}
MA_OPENSL_BUFFERQUEUE(Md->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)Md->opensl.pBufferQueuePlayback);
}
ma_device__on_notification_stopped(Md);
Mr Ms;
}
static Me ma_context_uninit__opensl(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_opensl);
(Mv)Mc;
ma_spinlock_lock(&g_maOpenSLSpinlock);
{
MA_ASSERT(g_maOpenSLInitCounter>0);
g_maOpenSLInitCounter-=1;
if (g_maOpenSLInitCounter==0) {
(*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
}
}
ma_spinlock_unlock(&g_maOpenSLSpinlock);
Mr Ms;
}
static Me ma_dlsym_SLInterfaceID__opensl(ma_context*Mc,const char*pName,ma_handle*pHandle)
{
ma_handle*p=(ma_handle*)ma_dlsym(ma_context_get_log(Mc),Mc->opensl.libOpenSLES,pName);
if (p==NULL) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol %s", pName);
Mr MA_NO_BACKEND;
}
*pHandle=*p;
Mr Ms;
}
static Me ma_context_init_engine_nolock__opensl(ma_context*Mc)
{
g_maOpenSLInitCounter+=1;
if (g_maOpenSLInitCounter==1) {
SLresult resultSL;
resultSL=((ma_slCreateEngine_proc)Mc->opensl.slCreateEngine)(&g_maEngineObjectSL,0,NULL,0,NULL,NULL);
if (resultSL !=SL_RESULT_SUCCESS) {
g_maOpenSLInitCounter-=1;
Mr ma_result_from_OpenSL(resultSL);
}
(*g_maEngineObjectSL)->Realize(g_maEngineObjectSL,SL_BOOLEAN_FALSE);
resultSL=(*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL,(SLInterfaceID)Mc->opensl.SL_IID_ENGINE,&g_maEngineSL);
if (resultSL !=SL_RESULT_SUCCESS) {
(*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
g_maOpenSLInitCounter-=1;
Mr ma_result_from_OpenSL(resultSL);
}
}
Mr Ms;
}
static Me ma_context_init__opensl(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
Me Mf;
#if !defined(MA_NO_RUNTIME_LINKING)
size_t i;
const char*libOpenSLESNames[]={
"libOpenSLES.so"
};
#endif
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
#if !defined(MA_NO_RUNTIME_LINKING)
for (i=0; i<ma_countof(libOpenSLESNames); i+=1) {
Mc->opensl.libOpenSLES=ma_dlopen(ma_context_get_log(Mc),libOpenSLESNames[i]);
if (Mc->opensl.libOpenSLES !=NULL) {
break;
}
}
if (Mc->opensl.libOpenSLES==NULL) {
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_INFO, "[OpenSL] Could not find libOpenSLES.so");
Mr MA_NO_BACKEND;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_ENGINE", &Mc->opensl.SL_IID_ENGINE);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_AUDIOIODEVICECAPABILITIES", &Mc->opensl.SL_IID_AUDIOIODEVICECAPABILITIES);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &Mc->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_RECORD", &Mc->opensl.SL_IID_RECORD);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_PLAY", &Mc->opensl.SL_IID_PLAY);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_OUTPUTMIX", &Mc->opensl.SL_IID_OUTPUTMIX);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mf = ma_dlsym_SLInterfaceID__opensl(Mc, "SL_IID_ANDROIDCONFIGURATION", &Mc->opensl.SL_IID_ANDROIDCONFIGURATION);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
Mr Mf;
}
Mc->opensl.slCreateEngine = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->opensl.libOpenSLES, "slCreateEngine");
if (Mc->opensl.slCreateEngine==NULL) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol slCreateEngine.");
Mr MA_NO_BACKEND;
}
#else
Mc->opensl.SL_IID_ENGINE=(ma_handle)SL_IID_ENGINE;
Mc->opensl.SL_IID_AUDIOIODEVICECAPABILITIES=(ma_handle)SL_IID_AUDIOIODEVICECAPABILITIES;
Mc->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE=(ma_handle)SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
Mc->opensl.SL_IID_RECORD=(ma_handle)SL_IID_RECORD;
Mc->opensl.SL_IID_PLAY=(ma_handle)SL_IID_PLAY;
Mc->opensl.SL_IID_OUTPUTMIX=(ma_handle)SL_IID_OUTPUTMIX;
Mc->opensl.SL_IID_ANDROIDCONFIGURATION=(ma_handle)SL_IID_ANDROIDCONFIGURATION;
Mc->opensl.slCreateEngine=(ma_proc)slCreateEngine;
#endif
ma_spinlock_lock(&g_maOpenSLSpinlock);
{
Mf=ma_context_init_engine_nolock__opensl(Mc);
}
ma_spinlock_unlock(&g_maOpenSLSpinlock);
if (Mf !=Ms) {
ma_dlclose(ma_context_get_log(Mc),Mc->opensl.libOpenSLES);
ma_log_post(ma_context_get_log(Mc), MA_LOG_LEVEL_INFO, "[OpenSL] Failed to initialize OpenSL engine.");
Mr Mf;
}
pCallbacks->onContextInit=ma_context_init__opensl;
pCallbacks->onContextUninit=ma_context_uninit__opensl;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__opensl;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__opensl;
pCallbacks->onDeviceInit=ma_device_init__opensl;
pCallbacks->onDeviceUninit=ma_device_uninit__opensl;
pCallbacks->onDeviceStart=ma_device_start__opensl;
pCallbacks->onDeviceStop=ma_device_stop__opensl;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
#ifdef MA_HAS_WEBAUDIO
#include <emscripten/emscripten.h>
#if (__EMSCRIPTEN_major__>3)||(__EMSCRIPTEN_major__==3&&(__EMSCRIPTEN_minor__>1||(__EMSCRIPTEN_minor__==1&&__EMSCRIPTEN_tiny__>=32)))
#include <emscripten/webaudio.h>
#define MA_SUPPORT_AUDIO_WORKLETS
#if (__EMSCRIPTEN_major__>3)||(__EMSCRIPTEN_major__==3&&(__EMSCRIPTEN_minor__>1||(__EMSCRIPTEN_minor__==1&&__EMSCRIPTEN_tiny__>=70)))
#define MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE
#endif
#endif
#if defined(MA_ENABLE_AUDIO_WORKLETS)&&defined(MA_SUPPORT_AUDIO_WORKLETS)
#define MA_USE_AUDIO_WORKLETS
#endif
#ifndef MA_AUDIO_WORKLETS_THREAD_STACK_SIZE
#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 131072
#endif
#if defined(MA_USE_AUDIO_WORKLETS)
#define MA_WEBAUDIO_LATENCY_HINT_BALANCED "balanced"
#define MA_WEBAUDIO_LATENCY_HINT_INTERACTIVE "interactive"
#define MA_WEBAUDIO_LATENCY_HINT_PLAYBACK "playback"
#endif
static ma_bool32 ma_is_capture_supported__webaudio()
{
Mr EM_ASM_INT({
Mr (navigator.mediaDevices !==undefined&&navigator.mediaDevices.getUserMedia !==undefined);
},0) !=0;
}
#ifdef __cplusplus
extern "C" {
#endif
Mv*EMSCRIPTEN_KEEPALIVE ma_malloc_emscripten(size_t sz,const ma_allocation_callbacks*pAllocationCallbacks)
{
Mr ma_malloc(sz,pAllocationCallbacks);
}
Mv EMSCRIPTEN_KEEPALIVE ma_free_emscripten(Mv*p,const ma_allocation_callbacks*pAllocationCallbacks)
{
ma_free(p,pAllocationCallbacks);
}
Mv EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device*Md,int frameCount,float*pFrames)
{
ma_device_handle_backend_data_callback(Md,NULL,pFrames,(M3)frameCount);
}
Mv EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_playback__webaudio(ma_device*Md,int frameCount,float*pFrames)
{
ma_device_handle_backend_data_callback(Md,pFrames,NULL,(M3)frameCount);
}
#ifdef __cplusplus
}
#endif
static Me ma_context_enumerate_devices__webaudio(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
ma_bool32 cbResult=MA_TRUE;
MA_ASSERT(Mc !=NULL);
MA_ASSERT(callback !=NULL);
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
deviceInfo.isDefault=MA_TRUE;
cbResult=callback(Mc,Mt,&deviceInfo,pUserData);
}
if (cbResult) {
if (ma_is_capture_supported__webaudio()) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name,sizeof(deviceInfo.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
deviceInfo.isDefault=MA_TRUE;
cbResult=callback(Mc,ma_device_type_capture,&deviceInfo,pUserData);
}
}
Mr Ms;
}
static Me ma_context_get_device_info__webaudio(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
MA_ASSERT(Mc !=NULL);
if (deviceType==ma_device_type_capture&&!ma_is_capture_supported__webaudio()) {
Mr MA_NO_DEVICE;
}
MA_ZERO_MEMORY(pDeviceInfo->id.webaudio,sizeof(pDeviceInfo->id.webaudio));
(Mv)pDeviceID;
if (deviceType==Mt) {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name,sizeof(pDeviceInfo->name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
}
pDeviceInfo->isDefault=MA_TRUE;
pDeviceInfo->nativeDataFormats[0].flags=0;
pDeviceInfo->nativeDataFormats[0].format=ma_format_unknown;
pDeviceInfo->nativeDataFormats[0].Mh=0;
pDeviceInfo->nativeDataFormats[0].sampleRate=EM_ASM_INT({
try {
var temp=new (window.AudioContext||window.webkitAudioContext)();
var sampleRate=temp.sampleRate;
temp.close();
Mr sampleRate;
} catch(e) {
Mr 0;
}
},0);
if (pDeviceInfo->nativeDataFormats[0].sampleRate==0) {
Mr MA_NO_DEVICE;
}
pDeviceInfo->nativeDataFormatCount=1;
Mr Ms;
}
static Me ma_device_uninit__webaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
#if defined(MA_USE_AUDIO_WORKLETS)
{
EM_ASM({
var device=window.miniaudio.get_device_by_index($0);
if (device.streamNode !==undefined) {
device.streamNode.disconnect();
device.streamNode=undefined;
}
device.Md=undefined;
},Md->webaudio.deviceIndex);
emscripten_destroy_web_audio_node(Md->webaudio.audioWorklet);
emscripten_destroy_audio_context(Md->webaudio.audioContext);
ma_free(Md->webaudio.pStackBuffer,&Md->Mc->allocationCallbacks);
}
#else
{
EM_ASM({
var device=window.miniaudio.get_device_by_index($0);
if (device.scriptNode !==undefined) {
device.scriptNode.onaudioprocess=function(e) {};
device.scriptNode.disconnect();
device.scriptNode=undefined;
}
if (device.streamNode !==undefined) {
device.streamNode.disconnect();
device.streamNode=undefined;
}
device.webaudio.close();
device.webaudio=undefined;
device.Md=undefined;
},Md->webaudio.deviceIndex);
}
#endif
EM_ASM({
window.miniaudio.untrack_device_by_index($0);
},Md->webaudio.deviceIndex);
ma_free(Md->webaudio.pIntermediaryBuffer,&Md->Mc->allocationCallbacks);
Mr Ms;
}
#if !defined(MA_USE_AUDIO_WORKLETS)
static M3 ma_calculate_period_size_in_frames_from_descriptor__webaudio(const ma_device_descriptor*pDescriptor,M3 nativeSampleRate,ma_performance_profile performanceProfile)
{
M3 periodSizeInFrames;
if (nativeSampleRate==0) {
nativeSampleRate=MA_DEFAULT_SAMPLE_RATE;
}
if (pDescriptor->periodSizeInFrames==0) {
if (pDescriptor->periodSizeInMilliseconds==0) {
if (performanceProfile==ma_performance_profile_low_latency) {
periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(33,nativeSampleRate);
} else {
periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(333,nativeSampleRate);
}
} else {
periodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds,nativeSampleRate);
}
} else {
periodSizeInFrames=pDescriptor->periodSizeInFrames;
}
if (periodSizeInFrames<256) {
periodSizeInFrames=256;
} else if (periodSizeInFrames>16384) {
periodSizeInFrames=16384;
} else {
periodSizeInFrames=ma_next_power_of_2(periodSizeInFrames);
}
Mr periodSizeInFrames;
}
#endif
#if defined(MA_USE_AUDIO_WORKLETS)
typedef struct
{
ma_device*Md;
const ma_device_config*Mo;
ma_device_descriptor*Mp;
ma_device_descriptor*pDescriptorCapture;
} ma_audio_worklet_thread_initialized_data;
static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount,const AudioSampleFrame*pInputs,int outputCount,AudioSampleFrame*pOutputs,int paramCount,const AudioParamFrame*pParams,Mv*pUserData)
{
ma_device*Md=(ma_device*)pUserData;
M3 frameCount;
(Mv)paramCount;
(Mv)pParams;
if (Md->type==Mt) {
frameCount=Md->playback.internalPeriodSizeInFrames;
} else {
frameCount=Md->capture.internalPeriodSizeInFrames;
}
if (ma_device_get_state(Md) !=ma_device_state_started) {
for (int i=0; i<outputCount; i+=1) {
MA_ZERO_MEMORY(pOutputs[i].data,pOutputs[i].numberOfChannels*frameCount*sizeof(float));
}
Mr EM_TRUE;
}
if (inputCount>0) {
for (M3 iChannel=0; iChannel<Md->capture.internalChannels; iChannel+=1) {
for (M3 iFrame=0; iFrame<frameCount; iFrame+=1) {
Md->webaudio.pIntermediaryBuffer[iFrame*Md->capture.internalChannels+iChannel]=pInputs[0].data[frameCount*iChannel+iFrame];
}
}
ma_device_process_pcm_frames_capture__webaudio(Md,frameCount,Md->webaudio.pIntermediaryBuffer);
}
if (outputCount>0) {
if (Md->type==ma_device_type_capture) {
MA_ZERO_MEMORY(pOutputs[0].data,frameCount*Md->playback.internalChannels*sizeof(float));
} else {
ma_device_process_pcm_frames_playback__webaudio(Md,frameCount,Md->webaudio.pIntermediaryBuffer);
for (M3 iChannel=0; iChannel<Md->playback.internalChannels; iChannel+=1) {
for (M3 iFrame=0; iFrame<frameCount; iFrame+=1) {
 pOutputs[0].data[frameCount*iChannel+iFrame]=Md->webaudio.pIntermediaryBuffer[iFrame*Md->playback.internalChannels+iChannel];
}
}
}
}
Mr EM_TRUE;
}
static Mv ma_audio_worklet_processor_created__webaudio(EMSCRIPTEN_WEBAUDIO_T audioContext,EM_BOOL success,Mv*pUserData)
{
ma_audio_worklet_thread_initialized_data*pParameters=(ma_audio_worklet_thread_initialized_data*)pUserData;
EmscriptenAudioWorkletNodeCreateOptions audioWorkletOptions;
int Mh=0;
size_t intermediaryBufferSizeInFrames;
int sampleRate;
if (success==EM_FALSE) {
pParameters->Md->webaudio.initResult=MA_ERROR;
ma_free(pParameters,&pParameters->Md->Mc->allocationCallbacks);
Mr;
}
MA_ZERO_OBJECT(&audioWorkletOptions);
if (pParameters->Mo->deviceType==ma_device_type_capture) {
Mh=(int)((pParameters->pDescriptorCapture->Mh>0)?pParameters->pDescriptorCapture->Mh:MA_DEFAULT_CHANNELS);
audioWorkletOptions.numberOfInputs=1;
} else {
Mh=(int)((pParameters->Mp->Mh>0)?pParameters->Mp->Mh:MA_DEFAULT_CHANNELS);
if (pParameters->Mo->deviceType==ma_device_type_duplex) {
audioWorkletOptions.numberOfInputs=1;
} else {
audioWorkletOptions.numberOfInputs=0;
}
}
audioWorkletOptions.numberOfOutputs=1;
audioWorkletOptions.outputChannelCounts=&Mh;
#if defined(MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE)
{
intermediaryBufferSizeInFrames=(size_t)emscripten_audio_context_quantum_size(audioContext);
}
#else
{
intermediaryBufferSizeInFrames=128;
}
#endif
pParameters->Md->webaudio.pIntermediaryBuffer=(float*)ma_malloc(intermediaryBufferSizeInFrames*(M3)Mh*sizeof(float),&pParameters->Md->Mc->allocationCallbacks);
if (pParameters->Md->webaudio.pIntermediaryBuffer==NULL) {
pParameters->Md->webaudio.initResult=MA_OUT_OF_MEMORY;
ma_free(pParameters,&pParameters->Md->Mc->allocationCallbacks);
Mr;
}
pParameters->Md->webaudio.audioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "miniaudio", &audioWorkletOptions, &ma_audio_worklet_process_callback__webaudio, pParameters->Md);
if (pParameters->Mo->deviceType==ma_device_type_capture||pParameters->Mo->deviceType==ma_device_type_duplex) {
Me attachmentResult=(Me)EM_ASM_INT({
var getUserMediaResult=0;
var audioWorklet=emscriptenGetAudioObject($0);
var audioContext=emscriptenGetAudioObject($1);
navigator.mediaDevices.getUserMedia({audio:true,video:false})
.then(function(stream) {
 audioContext.streamNode=audioContext.createMediaStreamSource(stream);
 audioContext.streamNode.connect(audioWorklet);
 audioWorklet.connect(audioContext.destination);
 getUserMediaResult=0;
})
.catch(function(error) {
 console.log("navigator.mediaDevices.getUserMedia Failed: " + error);
 getUserMediaResult=-1;
});
Mr getUserMediaResult;
},pParameters->Md->webaudio.audioWorklet,audioContext);
if (attachmentResult !=Ms) {
ma_log_postf(ma_device_get_log(pParameters->Md), MA_LOG_LEVEL_ERROR, "Web Audio: Failed to connect capture node.");
emscripten_destroy_web_audio_node(pParameters->Md->webaudio.audioWorklet);
pParameters->Md->webaudio.initResult=attachmentResult;
ma_free(pParameters,&pParameters->Md->Mc->allocationCallbacks);
Mr;
}
}
if (pParameters->Mo->deviceType==Mt) {
Me attachmentResult=(Me)EM_ASM_INT({
var audioWorklet=emscriptenGetAudioObject($0);
var audioContext=emscriptenGetAudioObject($1);
audioWorklet.connect(audioContext.destination);
Mr 0;
},pParameters->Md->webaudio.audioWorklet,audioContext);
if (attachmentResult !=Ms) {
ma_log_postf(ma_device_get_log(pParameters->Md), MA_LOG_LEVEL_ERROR, "Web Audio: Failed to connect playback node.");
pParameters->Md->webaudio.initResult=attachmentResult;
ma_free(pParameters,&pParameters->Md->Mc->allocationCallbacks);
Mr;
}
}
sampleRate=EM_ASM_INT({ Mr emscriptenGetAudioObject($0).sampleRate; },audioContext);
if (pParameters->pDescriptorCapture !=NULL) {
pParameters->pDescriptorCapture->format=ma_format_f32;
pParameters->pDescriptorCapture->Mh=(M3)Mh;
pParameters->pDescriptorCapture->sampleRate=(M3)sampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_webaudio,pParameters->pDescriptorCapture->channelMap,ma_countof(pParameters->pDescriptorCapture->channelMap),pParameters->pDescriptorCapture->Mh);
pParameters->pDescriptorCapture->periodSizeInFrames=intermediaryBufferSizeInFrames;
pParameters->pDescriptorCapture->periodCount=1;
}
if (pParameters->Mp !=NULL) {
pParameters->Mp->format=ma_format_f32;
pParameters->Mp->Mh=(M3)Mh;
pParameters->Mp->sampleRate=(M3)sampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_webaudio,pParameters->Mp->channelMap,ma_countof(pParameters->Mp->channelMap),pParameters->Mp->Mh);
pParameters->Mp->periodSizeInFrames=intermediaryBufferSizeInFrames;
pParameters->Mp->periodCount=1;
}
ma_log_postf(ma_device_get_log(pParameters->Md), MA_LOG_LEVEL_DEBUG, "AudioWorklets: Created worklet node: %d\n", pParameters->Md->webaudio.audioWorklet);
pParameters->Md->webaudio.initResult=Ms;
ma_free(pParameters,&pParameters->Md->Mc->allocationCallbacks);
}
static Mv ma_audio_worklet_thread_initialized__webaudio(EMSCRIPTEN_WEBAUDIO_T audioContext,EM_BOOL success,Mv*pUserData)
{
ma_audio_worklet_thread_initialized_data*pParameters=(ma_audio_worklet_thread_initialized_data*)pUserData;
WebAudioWorkletProcessorCreateOptions workletProcessorOptions;
MA_ASSERT(pParameters !=NULL);
if (success==EM_FALSE) {
pParameters->Md->webaudio.initResult=MA_ERROR;
Mr;
}
MA_ZERO_OBJECT(&workletProcessorOptions);
workletProcessorOptions.name = "miniaudio";
emscripten_create_wasm_audio_worklet_processor_async(audioContext,&workletProcessorOptions,ma_audio_worklet_processor_created__webaudio,pParameters);
}
#endif
static Me ma_device_init__webaudio(ma_device*Md,const ma_device_config*Mo,ma_device_descriptor*Mp,ma_device_descriptor*pDescriptorCapture)
{
if (Mo->deviceType==ma_device_type_loopback) {
Mr MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (((Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex)&&Mp->shareMode==ma_share_mode_exclusive)||
((Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex)&&pDescriptorCapture->shareMode==ma_share_mode_exclusive)) {
Mr MA_SHARE_MODE_NOT_SUPPORTED;
}
#if defined(MA_USE_AUDIO_WORKLETS)
{
EmscriptenWebAudioCreateAttributes audioContextAttributes;
ma_audio_worklet_thread_initialized_data*pInitParameters;
Mv*pStackBuffer;
if (Mo->performanceProfile==ma_performance_profile_conservative) {
audioContextAttributes.latencyHint=MA_WEBAUDIO_LATENCY_HINT_PLAYBACK;
} else {
audioContextAttributes.latencyHint=MA_WEBAUDIO_LATENCY_HINT_INTERACTIVE;
}
if (Mo->deviceType==Mt) {
audioContextAttributes.sampleRate=Mp->sampleRate;
} else {
audioContextAttributes.sampleRate=0;
}
Md->webaudio.audioContext=emscripten_create_audio_context(&audioContextAttributes);
pStackBuffer=ma_aligned_malloc(MA_AUDIO_WORKLETS_THREAD_STACK_SIZE,16,&Md->Mc->allocationCallbacks);
if (pStackBuffer==NULL) {
emscripten_destroy_audio_context(Md->webaudio.audioContext);
Mr MA_OUT_OF_MEMORY;
}
pInitParameters=(ma_audio_worklet_thread_initialized_data*)ma_malloc(sizeof(*pInitParameters),&Md->Mc->allocationCallbacks);
if (pInitParameters==NULL) {
ma_free(pStackBuffer,&Md->Mc->allocationCallbacks);
emscripten_destroy_audio_context(Md->webaudio.audioContext);
Mr MA_OUT_OF_MEMORY;
}
pInitParameters->Md=Md;
pInitParameters->Mo=Mo;
pInitParameters->Mp=Mp;
pInitParameters->pDescriptorCapture=pDescriptorCapture;
Md->webaudio.initResult=MA_BUSY;
{
emscripten_start_wasm_audio_worklet_thread_async(Md->webaudio.audioContext,pStackBuffer,MA_AUDIO_WORKLETS_THREAD_STACK_SIZE,ma_audio_worklet_thread_initialized__webaudio,pInitParameters);
}
while (Md->webaudio.initResult==MA_BUSY) { emscripten_sleep(1); }
if (Md->webaudio.initResult !=Ms) {
ma_free(pStackBuffer,&Md->Mc->allocationCallbacks);
emscripten_destroy_audio_context(Md->webaudio.audioContext);
Mr Md->webaudio.initResult;
}
Md->webaudio.deviceIndex=EM_ASM_INT({
Mr window.miniaudio.track_device({
webaudio:emscriptenGetAudioObject($0),state:1,Md:$1
});
},Md->webaudio.audioContext,Md);
Mr Ms;
}
#else
{
M3 deviceIndex;
M3 Mh;
M3 sampleRate;
M3 periodSizeInFrames;
if (Mo->deviceType==ma_device_type_capture) {
Mh=(pDescriptorCapture->Mh>0)?pDescriptorCapture->Mh:MA_DEFAULT_CHANNELS;
} else {
Mh=(Mp->Mh>0)?Mp->Mh:MA_DEFAULT_CHANNELS;
}
if (Mo->deviceType==Mt) {
sampleRate=Mp->sampleRate;
} else {
sampleRate=0;
}
if (Mo->deviceType==ma_device_type_capture) {
periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptorCapture,sampleRate,Mo->performanceProfile);
} else {
periodSizeInFrames=ma_calculate_period_size_in_frames_from_descriptor__webaudio(Mp,sampleRate,Mo->performanceProfile);
}
Md->webaudio.pIntermediaryBuffer=(float*)ma_malloc(periodSizeInFrames*Mh*sizeof(float),&Md->Mc->allocationCallbacks);
if (Md->webaudio.pIntermediaryBuffer==NULL) {
Mr MA_OUT_OF_MEMORY;
}
deviceIndex=EM_ASM_INT({
var deviceType=$0;
var Mh=$1;
var sampleRate=$2;
var bufferSize=$3;
var pIntermediaryBuffer=$4;
var Md=$5;
if (typeof(window.miniaudio)==='undefined') {
Mr-1;
}
var device={};
var audioContextOptions={};
if (deviceType==window.miniaudio.device_type.playback&&sampleRate !=0) {
audioContextOptions.sampleRate=sampleRate;
}
device.webaudio=new (window.AudioContext||window.webkitAudioContext)(audioContextOptions);
device.webaudio.suspend();
device.state=window.miniaudio.device_state.stopped;
var channelCountIn=0;
var channelCountOut=Mh;
if (deviceType !=window.miniaudio.device_type.playback) {
channelCountIn=Mh;
}
device.scriptNode=device.webaudio.createScriptProcessor(bufferSize,channelCountIn,channelCountOut);
device.scriptNode.onaudioprocess=function(e) {
if (device.intermediaryBufferView==null||device.intermediaryBufferView.length==0) {
 device.intermediaryBufferView=new Float32Array(HEAPF32.buffer,pIntermediaryBuffer,bufferSize*Mh);
}
if (deviceType==window.miniaudio.device_type.capture||deviceType==window.miniaudio.device_type.duplex) {
 for (var iChannel=0; iChannel<Mh; iChannel+=1) {
 var inputBuffer=e.inputBuffer.getChannelData(iChannel);
 var intermediaryBuffer=device.intermediaryBufferView;
 for (var iFrame=0; iFrame<bufferSize; iFrame+=1) {
 intermediaryBuffer[iFrame*Mh+iChannel]=inputBuffer[iFrame];
 }
 }
 _ma_device_process_pcm_frames_capture__webaudio(Md,bufferSize,pIntermediaryBuffer);
}
if (deviceType==window.miniaudio.device_type.playback||deviceType==window.miniaudio.device_type.duplex) {
 _ma_device_process_pcm_frames_playback__webaudio(Md,bufferSize,pIntermediaryBuffer);
 for (var iChannel=0; iChannel<e.outputBuffer.numberOfChannels;++iChannel) {
 var outputBuffer=e.outputBuffer.getChannelData(iChannel);
 var intermediaryBuffer=device.intermediaryBufferView;
 for (var iFrame=0; iFrame<bufferSize; iFrame+=1) {
 outputBuffer[iFrame]=intermediaryBuffer[iFrame*Mh+iChannel];
 }
 }
} else {
 for (var iChannel=0; iChannel<e.outputBuffer.numberOfChannels;++iChannel) {
 e.outputBuffer.getChannelData(iChannel).fill(0.0);
 }
}
};
if (deviceType==window.miniaudio.device_type.capture||deviceType==window.miniaudio.device_type.duplex) {
navigator.mediaDevices.getUserMedia({audio:true,video:false})
 .then(function(stream) {
 device.streamNode=device.webaudio.createMediaStreamSource(stream);
 device.streamNode.connect(device.scriptNode);
 device.scriptNode.connect(device.webaudio.destination);
 })
 .catch(function(error) {
 console.log("Failed to get user media: " + error);
 });
}
if (deviceType==window.miniaudio.device_type.playback) {
device.scriptNode.connect(device.webaudio.destination);
}
device.Md=Md;
Mr window.miniaudio.track_device(device);
},Mo->deviceType,Mh,sampleRate,periodSizeInFrames,Md->webaudio.pIntermediaryBuffer,Md);
if (deviceIndex<0) {
Mr MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
Md->webaudio.deviceIndex=deviceIndex;
sampleRate=(M3)EM_ASM_INT({ Mr window.miniaudio.get_device_by_index($0).webaudio.sampleRate; },deviceIndex);
if (pDescriptorCapture !=NULL) {
pDescriptorCapture->format=ma_format_f32;
pDescriptorCapture->Mh=Mh;
pDescriptorCapture->sampleRate=sampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_webaudio,pDescriptorCapture->channelMap,ma_countof(pDescriptorCapture->channelMap),pDescriptorCapture->Mh);
pDescriptorCapture->periodSizeInFrames=periodSizeInFrames;
pDescriptorCapture->periodCount=1;
}
if (Mp !=NULL) {
Mp->format=ma_format_f32;
Mp->Mh=Mh;
Mp->sampleRate=sampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_webaudio,Mp->channelMap,ma_countof(Mp->channelMap),Mp->Mh);
Mp->periodSizeInFrames=periodSizeInFrames;
Mp->periodCount=1;
}
Mr Ms;
}
#endif
}
static Me ma_device_start__webaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
EM_ASM({
var device=window.miniaudio.get_device_by_index($0);
device.webaudio.resume();
device.state=window.miniaudio.device_state.started;
},Md->webaudio.deviceIndex);
Mr Ms;
}
static Me ma_device_stop__webaudio(ma_device*Md)
{
MA_ASSERT(Md !=NULL);
EM_ASM({
var device=window.miniaudio.get_device_by_index($0);
device.webaudio.suspend();
device.state=window.miniaudio.device_state.stopped;
},Md->webaudio.deviceIndex);
ma_device__on_notification_stopped(Md);
Mr Ms;
}
static Me ma_context_uninit__webaudio(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
MA_ASSERT(Mc->backend==ma_backend_webaudio);
(Mv)Mc;
EM_ASM({
if (typeof(window.miniaudio) !=='undefined') {
miniaudio.unlock_event_types.map(function(event_type) {
document.removeEventListener(event_type,miniaudio.unlock,true);
});
window.miniaudio.referenceCount-=1;
if (window.miniaudio.referenceCount===0) {
delete window.miniaudio;
}
}
});
Mr Ms;
}
static Me ma_context_init__webaudio(ma_context*Mc,const ma_context_config*Mo,ma_backend_callbacks*pCallbacks)
{
int resultFromJS;
MA_ASSERT(Mc !=NULL);
(Mv)Mo;
resultFromJS=EM_ASM_INT({
if (typeof window==='undefined'||(window.AudioContext||window.webkitAudioContext)===undefined) {
Mr 0;
}
if (typeof(window.miniaudio)==='undefined') {
window.miniaudio={
referenceCount:0
};
window.miniaudio.device_type={};
window.miniaudio.device_type.playback=$0;
window.miniaudio.device_type.capture=$1;
window.miniaudio.device_type.duplex=$2;
window.miniaudio.device_state={};
window.miniaudio.device_state.stopped=$3;
window.miniaudio.device_state.started=$4;
let miniaudio=window.miniaudio;
miniaudio.devices=[];
miniaudio.track_device=function(device) {
for (var iDevice=0; iDevice<miniaudio.devices.length;++iDevice) {
 if (miniaudio.devices[iDevice]==null) {
 miniaudio.devices[iDevice]=device;
 Mr iDevice;
 }
}
miniaudio.devices.push(device);
Mr miniaudio.devices.length-1;
};
miniaudio.untrack_device_by_index=function(deviceIndex) {
miniaudio.devices[deviceIndex]=null;
while (miniaudio.devices.length>0) {
 if (miniaudio.devices[miniaudio.devices.length-1]==null) {
 miniaudio.devices.pop();
 } else {
 break;
 }
}
};
miniaudio.untrack_device=function(device) {
for (var iDevice=0; iDevice<miniaudio.devices.length;++iDevice) {
 if (miniaudio.devices[iDevice]==device) {
 Mr miniaudio.untrack_device_by_index(iDevice);
 }
}
};
miniaudio.get_device_by_index=function(deviceIndex) {
Mr miniaudio.devices[deviceIndex];
};
miniaudio.unlock_event_types=(function(){
Mr ['touchend','click'];
})();
miniaudio.unlock=function() {
for(var i=0; i<miniaudio.devices.length;++i) {
 var device=miniaudio.devices[i];
 if (device !=null&&
 device.webaudio !=null&&
 device.state===miniaudio.device_state.started) {
 device.webaudio.resume().then(()=>{
 _ma_device__on_notification_unlocked(device.Md);
 },(error) => {console.error("Failed to resume audiocontext", error);
 });
 }
}
miniaudio.unlock_event_types.map(function(event_type) {
 document.removeEventListener(event_type,miniaudio.unlock,true);
});
};
miniaudio.unlock_event_types.map(function(event_type) {
document.addEventListener(event_type,miniaudio.unlock,true);
});
}
window.miniaudio.referenceCount+=1;
Mr 1;
},Mt,ma_device_type_capture,ma_device_type_duplex,ma_device_state_stopped,ma_device_state_started);
if (resultFromJS !=1) {
Mr MA_FAILED_TO_INIT_BACKEND;
}
pCallbacks->onContextInit=ma_context_init__webaudio;
pCallbacks->onContextUninit=ma_context_uninit__webaudio;
pCallbacks->onContextEnumerateDevices=ma_context_enumerate_devices__webaudio;
pCallbacks->onContextGetDeviceInfo=ma_context_get_device_info__webaudio;
pCallbacks->onDeviceInit=ma_device_init__webaudio;
pCallbacks->onDeviceUninit=ma_device_uninit__webaudio;
pCallbacks->onDeviceStart=ma_device_start__webaudio;
pCallbacks->onDeviceStop=ma_device_stop__webaudio;
pCallbacks->onDeviceRead=NULL;
pCallbacks->onDeviceWrite=NULL;
pCallbacks->onDeviceDataLoop=NULL;
Mr Ms;
}
#endif
static ma_bool32 ma__is_channel_map_valid(const ma_channel*pChannelMap,M3 Mh)
{
if (pChannelMap !=NULL&&pChannelMap[0] !=MA_CHANNEL_NONE) {
M3 iChannel;
if (Mh==0||Mh>MA_MAX_CHANNELS) {
Mr MA_FALSE;
}
for (iChannel=0; iChannel<Mh;++iChannel) {
M3 jChannel;
for (jChannel=iChannel+1; jChannel<Mh;++jChannel) {
if (pChannelMap[iChannel]==pChannelMap[jChannel]) {
 Mr MA_FALSE;
}
}
}
}
Mr MA_TRUE;
}
static ma_bool32 ma_context_is_backend_asynchronous(ma_context*Mc)
{
MA_ASSERT(Mc !=NULL);
if (Mc->callbacks.onDeviceRead==NULL&&Mc->callbacks.onDeviceWrite==NULL) {
if (Mc->callbacks.onDeviceDataLoop==NULL) {
Mr MA_TRUE;
} else {
Mr MA_FALSE;
}
} else {
Mr MA_FALSE;
}
}
static Me ma_device__post_init_setup(ma_device*Md,ma_device_type deviceType)
{
Me Mf;
MA_ASSERT(Md !=NULL);
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_duplex||deviceType==ma_device_type_loopback) {
if (Md->capture.format==ma_format_unknown) {
Md->capture.format=Md->capture.internalFormat;
}
if (Md->capture.Mh==0) {
Md->capture.Mh=Md->capture.internalChannels;
}
if (Md->capture.channelMap[0]==MA_CHANNEL_NONE) {
MA_ASSERT(Md->capture.Mh<=MA_MAX_CHANNELS);
if (Md->capture.internalChannels==Md->capture.Mh) {
ma_channel_map_copy(Md->capture.channelMap,Md->capture.internalChannelMap,Md->capture.Mh);
} else {
if (Md->capture.channelMixMode==ma_channel_mix_mode_simple) {
 ma_channel_map_init_blank(Md->capture.channelMap,Md->capture.Mh);
} else {
 ma_channel_map_init_standard(ma_standard_channel_map_default,Md->capture.channelMap,ma_countof(Md->capture.channelMap),Md->capture.Mh);
}
}
}
}
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
if (Md->playback.format==ma_format_unknown) {
Md->playback.format=Md->playback.internalFormat;
}
if (Md->playback.Mh==0) {
Md->playback.Mh=Md->playback.internalChannels;
}
if (Md->playback.channelMap[0]==MA_CHANNEL_NONE) {
MA_ASSERT(Md->playback.Mh<=MA_MAX_CHANNELS);
if (Md->playback.internalChannels==Md->playback.Mh) {
ma_channel_map_copy(Md->playback.channelMap,Md->playback.internalChannelMap,Md->playback.Mh);
} else {
if (Md->playback.channelMixMode==ma_channel_mix_mode_simple) {
 ma_channel_map_init_blank(Md->playback.channelMap,Md->playback.Mh);
} else {
 ma_channel_map_init_standard(ma_standard_channel_map_default,Md->playback.channelMap,ma_countof(Md->playback.channelMap),Md->playback.Mh);
}
}
}
}
if (Md->sampleRate==0) {
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_duplex||deviceType==ma_device_type_loopback) {
Md->sampleRate=Md->capture.internalSampleRate;
} else {
Md->sampleRate=Md->playback.internalSampleRate;
}
}
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_duplex||deviceType==ma_device_type_loopback) {
ma_data_converter_config converterConfig=ma_data_converter_config_init_default();
converterConfig.formatIn=Md->capture.internalFormat;
converterConfig.channelsIn=Md->capture.internalChannels;
converterConfig.sampleRateIn=Md->capture.internalSampleRate;
converterConfig.pChannelMapIn=Md->capture.internalChannelMap;
converterConfig.formatOut=Md->capture.format;
converterConfig.channelsOut=Md->capture.Mh;
converterConfig.sampleRateOut=Md->sampleRate;
converterConfig.pChannelMapOut=Md->capture.channelMap;
converterConfig.channelMixMode=Md->capture.channelMixMode;
converterConfig.calculateLFEFromSpatialChannels=Md->capture.calculateLFEFromSpatialChannels;
converterConfig.allowDynamicSampleRate=MA_FALSE;
converterConfig.resampling.algorithm=Md->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder=Md->resampling.linear.lpfOrder;
converterConfig.resampling.pBackendVTable=Md->resampling.pBackendVTable;
converterConfig.resampling.pBackendUserData=Md->resampling.pBackendUserData;
if (ma_device_get_state(Md) !=ma_device_state_uninitialized) {
ma_data_converter_uninit(&Md->capture.converter,&Md->Mc->allocationCallbacks);
}
Mf=ma_data_converter_init(&converterConfig,&Md->Mc->allocationCallbacks,&Md->capture.converter);
if (Mf !=Ms) {
Mr Mf;
}
}
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
ma_data_converter_config converterConfig=ma_data_converter_config_init_default();
converterConfig.formatIn=Md->playback.format;
converterConfig.channelsIn=Md->playback.Mh;
converterConfig.sampleRateIn=Md->sampleRate;
converterConfig.pChannelMapIn=Md->playback.channelMap;
converterConfig.formatOut=Md->playback.internalFormat;
converterConfig.channelsOut=Md->playback.internalChannels;
converterConfig.sampleRateOut=Md->playback.internalSampleRate;
converterConfig.pChannelMapOut=Md->playback.internalChannelMap;
converterConfig.channelMixMode=Md->playback.channelMixMode;
converterConfig.calculateLFEFromSpatialChannels=Md->playback.calculateLFEFromSpatialChannels;
converterConfig.allowDynamicSampleRate=MA_FALSE;
converterConfig.resampling.algorithm=Md->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder=Md->resampling.linear.lpfOrder;
converterConfig.resampling.pBackendVTable=Md->resampling.pBackendVTable;
converterConfig.resampling.pBackendUserData=Md->resampling.pBackendUserData;
if (ma_device_get_state(Md) !=ma_device_state_uninitialized) {
ma_data_converter_uninit(&Md->playback.converter,&Md->Mc->allocationCallbacks);
}
Mf=ma_data_converter_init(&converterConfig,&Md->Mc->allocationCallbacks,&Md->playback.converter);
if (Mf !=Ms) {
Mr Mf;
}
}
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
M6 unused;
Md->playback.inputCacheConsumed=0;
Md->playback.inputCacheRemaining=0;
if (Md->type==ma_device_type_duplex||
ma_data_converter_get_required_input_frame_count(&Md->playback.converter,1,&unused) !=Ms)
{
Mv*pNewInputCache;
M6 newInputCacheCap;
M6 newInputCacheSizeInBytes;
newInputCacheCap=ma_calculate_frame_count_after_resampling(Md->playback.internalSampleRate,Md->sampleRate,Md->playback.internalPeriodSizeInFrames);
newInputCacheSizeInBytes=newInputCacheCap*ma_get_bytes_per_frame(Md->playback.format,Md->playback.Mh);
if (newInputCacheSizeInBytes>MA_SIZE_MAX) {
ma_free(Md->playback.pInputCache,&Md->Mc->allocationCallbacks);
Md->playback.pInputCache=NULL;
Md->playback.inputCacheCap=0;
Mr MA_OUT_OF_MEMORY;
}
pNewInputCache=ma_realloc(Md->playback.pInputCache,(size_t)newInputCacheSizeInBytes,&Md->Mc->allocationCallbacks);
if (pNewInputCache==NULL) {
ma_free(Md->playback.pInputCache,&Md->Mc->allocationCallbacks);
Md->playback.pInputCache=NULL;
Md->playback.inputCacheCap=0;
Mr MA_OUT_OF_MEMORY;
}
Md->playback.pInputCache=pNewInputCache;
Md->playback.inputCacheCap=newInputCacheCap;
} else {
ma_free(Md->playback.pInputCache,&Md->Mc->allocationCallbacks);
Md->playback.pInputCache=NULL;
Md->playback.inputCacheCap=0;
}
}
Mr Ms;
}
MA_API Me ma_device_post_init(ma_device*Md,ma_device_type deviceType,const ma_device_descriptor*Mp,const ma_device_descriptor*pDescriptorCapture)
{
Me Mf;
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_duplex||deviceType==ma_device_type_loopback) {
if (ma_device_descriptor_is_valid(pDescriptorCapture)==MA_FALSE) {
Mr MA_INVALID_ARGS;
}
Md->capture.internalFormat=pDescriptorCapture->format;
Md->capture.internalChannels=pDescriptorCapture->Mh;
Md->capture.internalSampleRate=pDescriptorCapture->sampleRate;
MA_COPY_MEMORY(Md->capture.internalChannelMap,pDescriptorCapture->channelMap,sizeof(pDescriptorCapture->channelMap));
Md->capture.internalPeriodSizeInFrames=pDescriptorCapture->periodSizeInFrames;
Md->capture.internalPeriods=pDescriptorCapture->periodCount;
if (Md->capture.internalPeriodSizeInFrames==0) {
Md->capture.internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptorCapture->periodSizeInMilliseconds,pDescriptorCapture->sampleRate);
}
}
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
if (ma_device_descriptor_is_valid(Mp)==MA_FALSE) {
Mr MA_INVALID_ARGS;
}
Md->playback.internalFormat=Mp->format;
Md->playback.internalChannels=Mp->Mh;
Md->playback.internalSampleRate=Mp->sampleRate;
MA_COPY_MEMORY(Md->playback.internalChannelMap,Mp->channelMap,sizeof(Mp->channelMap));
Md->playback.internalPeriodSizeInFrames=Mp->periodSizeInFrames;
Md->playback.internalPeriods=Mp->periodCount;
if (Md->playback.internalPeriodSizeInFrames==0) {
Md->playback.internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(Mp->periodSizeInMilliseconds,Mp->sampleRate);
}
}
{
ma_device_info deviceInfo;
if (deviceType==ma_device_type_capture||deviceType==ma_device_type_duplex||deviceType==ma_device_type_loopback) {
Mf=ma_device_get_info(Md,ma_device_type_capture,&deviceInfo);
if (Mf==Ms) {
ma_strncpy_s(Md->capture.name,sizeof(Md->capture.name),deviceInfo.name,(size_t)-1);
} else {
if (pDescriptorCapture->pDeviceID==NULL) {
 ma_strncpy_s(Md->capture.name,sizeof(Md->capture.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
} else {
 ma_strncpy_s(Md->capture.name, sizeof(Md->capture.name), "Capture Device", (size_t)-1);
}
}
}
if (deviceType==Mt||deviceType==ma_device_type_duplex) {
Mf=ma_device_get_info(Md,Mt,&deviceInfo);
if (Mf==Ms) {
ma_strncpy_s(Md->playback.name,sizeof(Md->playback.name),deviceInfo.name,(size_t)-1);
} else {
if (Mp->pDeviceID==NULL) {
 ma_strncpy_s(Md->playback.name,sizeof(Md->playback.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
 ma_strncpy_s(Md->playback.name, sizeof(Md->playback.name), "Playback Device", (size_t)-1);
}
}
}
}
Mr ma_device__post_init_setup(Md,deviceType);
}
static ma_thread_result MA_THREADCALL ma_worker_thread(Mv*pData)
{
ma_device*Md=(ma_device*)pData;
#ifdef MA_WIN32
HRESULT CoInitializeResult;
#endif
MA_ASSERT(Md !=NULL);
#ifdef MA_WIN32
CoInitializeResult=ma_CoInitializeEx(Md->Mc,NULL,MA_COINIT_VALUE);
#endif
ma_device__set_state(Md,ma_device_state_stopped);
ma_event_signal(&Md->stopEvent);
for (;;) {
Me startResult;
Me stopResult;
ma_event_wait(&Md->wakeupEvent);
Md->workResult=Ms;
if (ma_device_get_state(Md)==ma_device_state_uninitialized) {
break;
}
MA_ASSERT(ma_device_get_state(Md)==ma_device_state_starting);
if (Md->Mc->callbacks.onDeviceStart !=NULL) {
startResult=Md->Mc->callbacks.onDeviceStart(Md);
} else {
startResult=Ms;
}
if (startResult !=Ms) {
Md->workResult=startResult;
ma_event_signal(&Md->startEvent);
continue;
}
ma_device__set_state(Md,ma_device_state_started);
ma_event_signal(&Md->startEvent);
ma_device__on_notification_started(Md);
if (Md->Mc->callbacks.onDeviceDataLoop !=NULL) {
Md->Mc->callbacks.onDeviceDataLoop(Md);
} else {
ma_device_audio_thread__default_read_write(Md);
}
if (Md->Mc->callbacks.onDeviceStop !=NULL) {
stopResult=Md->Mc->callbacks.onDeviceStop(Md);
} else {
stopResult=Ms;
}
if (stopResult==Ms) {
ma_device__on_notification_stopped(Md);
}
if (ma_device_get_state(Md)==ma_device_state_uninitialized) {
break;
}
ma_device__set_state(Md,ma_device_state_stopped);
ma_event_signal(&Md->stopEvent);
}
#ifdef MA_WIN32
if (CoInitializeResult==S_OK) {
ma_CoUninitialize(Md->Mc);
}
#endif
Mr (ma_thread_result)0;
}
static ma_bool32 ma_device__is_initialized(ma_device*Md)
{
if (Md==NULL) {
Mr MA_FALSE;
}
Mr ma_device_get_state(Md) !=ma_device_state_uninitialized;
}
#ifdef MA_WIN32
static Me ma_context_uninit_backend_apis__win32(ma_context*Mc)
{
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
if (Mc->win32.CoInitializeResult==S_OK) {
ma_CoUninitialize(Mc);
}
#if defined(MA_WIN32_DESKTOP)
ma_dlclose(ma_context_get_log(Mc),Mc->win32.hUser32DLL);
ma_dlclose(ma_context_get_log(Mc),Mc->win32.hAdvapi32DLL);
#endif
ma_dlclose(ma_context_get_log(Mc),Mc->win32.hOle32DLL);
#else
(Mv)Mc;
#endif
Mr Ms;
}
static Me ma_context_init_backend_apis__win32(ma_context*Mc)
{
#if defined(MA_WIN32_DESKTOP)||defined(MA_WIN32_GDK)
#if defined(MA_WIN32_DESKTOP)
Mc->win32.hUser32DLL = ma_dlopen(ma_context_get_log(Mc), "user32.dll");
if (Mc->win32.hUser32DLL==NULL) {
Mr MA_FAILED_TO_INIT_BACKEND;
}
Mc->win32.GetForegroundWindow = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hUser32DLL, "GetForegroundWindow");
Mc->win32.GetDesktopWindow = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hUser32DLL, "GetDesktopWindow");
Mc->win32.hAdvapi32DLL = ma_dlopen(ma_context_get_log(Mc), "advapi32.dll");
if (Mc->win32.hAdvapi32DLL==NULL) {
Mr MA_FAILED_TO_INIT_BACKEND;
}
Mc->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hAdvapi32DLL, "RegOpenKeyExA");
Mc->win32.RegCloseKey = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hAdvapi32DLL, "RegCloseKey");
Mc->win32.RegQueryValueExA = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hAdvapi32DLL, "RegQueryValueExA");
#endif
Mc->win32.hOle32DLL = ma_dlopen(ma_context_get_log(Mc), "ole32.dll");
if (Mc->win32.hOle32DLL==NULL) {
Mr MA_FAILED_TO_INIT_BACKEND;
}
Mc->win32.CoInitialize = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "CoInitialize");
Mc->win32.CoInitializeEx = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "CoInitializeEx");
Mc->win32.CoUninitialize = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "CoUninitialize");
Mc->win32.CoCreateInstance = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "CoCreateInstance");
Mc->win32.CoTaskMemFree = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "CoTaskMemFree");
Mc->win32.PropVariantClear = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "PropVariantClear");
Mc->win32.StringFromGUID2 = (ma_proc)ma_dlsym(ma_context_get_log(Mc), Mc->win32.hOle32DLL, "StringFromGUID2");
#else
(Mv)Mc;
#endif
Mc->win32.CoInitializeResult=ma_CoInitializeEx(Mc,NULL,MA_COINIT_VALUE);
Mr Ms;
}
#else
static Me ma_context_uninit_backend_apis__nix(ma_context*Mc)
{
(Mv)Mc;
Mr Ms;
}
static Me ma_context_init_backend_apis__nix(ma_context*Mc)
{
(Mv)Mc;
Mr Ms;
}
#endif
static Me ma_context_init_backend_apis(ma_context*Mc)
{
Me Mf;
#ifdef MA_WIN32
Mf=ma_context_init_backend_apis__win32(Mc);
#else
Mf=ma_context_init_backend_apis__nix(Mc);
#endif
Mr Mf;
}
static Me ma_context_uninit_backend_apis(ma_context*Mc)
{
Me Mf;
#ifdef MA_WIN32
Mf=ma_context_uninit_backend_apis__win32(Mc);
#else
Mf=ma_context_uninit_backend_apis__nix(Mc);
#endif
Mr Mf;
}
#ifndef MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY
#define MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY 32
#endif
MA_API ma_device_job_thread_config ma_device_job_thread_config_init(Mv)
{
ma_device_job_thread_config config;
MA_ZERO_OBJECT(&config);
config.noThread=MA_FALSE;
config.jobQueueCapacity=MA_DEFAULT_DEVICE_JOB_QUEUE_CAPACITY;
config.jobQueueFlags=0;
Mr config;
}
static ma_thread_result MA_THREADCALL ma_device_job_thread_entry(Mv*pUserData)
{
ma_device_job_thread*pJobThread=(ma_device_job_thread*)pUserData;
MA_ASSERT(pJobThread !=NULL);
for (;;) {
Me Mf;
ma_job job;
Mf=ma_device_job_thread_next(pJobThread,&job);
if (Mf !=Ms) {
break;
}
if (job.toc.breakup.code==MA_JOB_TYPE_QUIT) {
break;
}
ma_job_process(&job);
}
Mr (ma_thread_result)0;
}
MA_API Me ma_device_job_thread_init(const ma_device_job_thread_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_device_job_thread*pJobThread)
{
Me Mf;
ma_job_queue_config jobQueueConfig;
if (pJobThread==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pJobThread);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
jobQueueConfig=ma_job_queue_config_init(Mo->jobQueueFlags,Mo->jobQueueCapacity);
Mf=ma_job_queue_init(&jobQueueConfig,pAllocationCallbacks,&pJobThread->jobQueue);
if (Mf !=Ms) {
Mr Mf;
}
if (Mo->noThread==MA_FALSE) {
Mf=ma_thread_create(&pJobThread->thread,ma_thread_priority_normal,0,ma_device_job_thread_entry,pJobThread,pAllocationCallbacks);
if (Mf !=Ms) {
ma_job_queue_uninit(&pJobThread->jobQueue,pAllocationCallbacks);
Mr Mf;
}
pJobThread->_hasThread=MA_TRUE;
} else {
pJobThread->_hasThread=MA_FALSE;
}
Mr Ms;
}
MA_API Mv ma_device_job_thread_uninit(ma_device_job_thread*pJobThread,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pJobThread==NULL) {
Mr;
}
{
ma_job job=ma_job_init(MA_JOB_TYPE_QUIT);
ma_device_job_thread_post(pJobThread,&job);
}
if (pJobThread->_hasThread) {
ma_thread_wait(&pJobThread->thread);
}
ma_job_queue_uninit(&pJobThread->jobQueue,pAllocationCallbacks);
}
MA_API Me ma_device_job_thread_post(ma_device_job_thread*pJobThread,const ma_job*pJob)
{
if (pJobThread==NULL||pJob==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_job_queue_post(&pJobThread->jobQueue,pJob);
}
MA_API Me ma_device_job_thread_next(ma_device_job_thread*pJobThread,ma_job*pJob)
{
if (pJob==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pJob);
if (pJobThread==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_job_queue_next(&pJobThread->jobQueue,pJob);
}
MA_API ma_bool32 ma_device_id_equal(const ma_device_id*pA,const ma_device_id*pB)
{
size_t i;
if (pA==NULL||pB==NULL) {
Mr MA_FALSE;
}
for (i=0; i<sizeof(ma_device_id); i+=1) {
if (((const char*)pA)[i] !=((const char*)pB)[i]) {
Mr MA_FALSE;
}
}
Mr MA_TRUE;
}
MA_API ma_context_config ma_context_config_init(Mv)
{
ma_context_config config;
MA_ZERO_OBJECT(&config);
Mr config;
}
MA_API Me ma_context_init(const ma_backend backends[],M3 backendCount,const ma_context_config*Mo,ma_context*Mc)
{
Me Mf;
ma_context_config defaultConfig;
ma_backend defaultBackends[ma_backend_null+1];
M3 iBackend;
ma_backend*pBackendsToIterate;
M3 backendsToIterateCount;
if (Mc==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(Mc);
if (Mo==NULL) {
defaultConfig=ma_context_config_init();
Mo=&defaultConfig;
}
Mf=ma_allocation_callbacks_init_copy(&Mc->allocationCallbacks,&Mo->allocationCallbacks);
if (Mf !=Ms) {
Mr Mf;
}
if (Mo->pLog !=NULL) {
Mc->pLog=Mo->pLog;
} else {
Mf=ma_log_init(&Mc->allocationCallbacks,&Mc->log);
if (Mf==Ms) {
Mc->pLog=&Mc->log;
} else {
Mc->pLog=NULL;
}
}
Mc->threadPriority=Mo->threadPriority;
Mc->threadStackSize=Mo->threadStackSize;
Mc->pUserData=Mo->pUserData;
Mf=ma_context_init_backend_apis(Mc);
if (Mf !=Ms) {
Mr Mf;
}
for (iBackend=0; iBackend<=ma_backend_null;++iBackend) {
defaultBackends[iBackend]=(ma_backend)iBackend;
}
pBackendsToIterate=(ma_backend*)backends;
backendsToIterateCount=backendCount;
if (pBackendsToIterate==NULL) {
pBackendsToIterate=(ma_backend*)defaultBackends;
backendsToIterateCount=ma_countof(defaultBackends);
}
MA_ASSERT(pBackendsToIterate !=NULL);
for (iBackend=0; iBackend<backendsToIterateCount; iBackend+=1) {
ma_backend backend=pBackendsToIterate[iBackend];
MA_ZERO_OBJECT(&Mc->callbacks);
switch (backend) {
#ifdef MA_HAS_WASAPI
case ma_backend_wasapi:
{
Mc->callbacks.onContextInit=ma_context_init__wasapi;
} break;
#endif
#ifdef MA_HAS_DSOUND
case ma_backend_dsound:
{
Mc->callbacks.onContextInit=ma_context_init__dsound;
} break;
#endif
#ifdef MA_HAS_WINMM
case ma_backend_winmm:
{
Mc->callbacks.onContextInit=ma_context_init__winmm;
} break;
#endif
#ifdef MA_HAS_COREAUDIO
case ma_backend_coreaudio:
{
Mc->callbacks.onContextInit=ma_context_init__coreaudio;
} break;
#endif
#ifdef MA_HAS_SNDIO
case ma_backend_sndio:
{
Mc->callbacks.onContextInit=ma_context_init__sndio;
} break;
#endif
#ifdef MA_HAS_AUDIO4
case ma_backend_audio4:
{
Mc->callbacks.onContextInit=ma_context_init__audio4;
} break;
#endif
#ifdef MA_HAS_OSS
case ma_backend_oss:
{
Mc->callbacks.onContextInit=ma_context_init__oss;
} break;
#endif
#ifdef MA_HAS_PULSEAUDIO
case ma_backend_pulseaudio:
{
Mc->callbacks.onContextInit=ma_context_init__pulse;
} break;
#endif
#ifdef MA_HAS_ALSA
case ma_backend_alsa:
{
Mc->callbacks.onContextInit=ma_context_init__alsa;
} break;
#endif
#ifdef MA_HAS_JACK
case ma_backend_jack:
{
Mc->callbacks.onContextInit=ma_context_init__jack;
} break;
#endif
#ifdef MA_HAS_AAUDIO
case ma_backend_aaudio:
{
if (ma_is_backend_enabled(backend)) {
 Mc->callbacks.onContextInit=ma_context_init__aaudio;
}
} break;
#endif
#ifdef MA_HAS_OPENSL
case ma_backend_opensl:
{
if (ma_is_backend_enabled(backend)) {
 Mc->callbacks.onContextInit=ma_context_init__opensl;
}
} break;
#endif
#ifdef MA_HAS_WEBAUDIO
case ma_backend_webaudio:
{
Mc->callbacks.onContextInit=ma_context_init__webaudio;
} break;
#endif
#ifdef MA_HAS_CUSTOM
case ma_backend_custom:
{
Mc->callbacks=Mo->custom;
} break;
#endif
#ifdef MA_HAS_NULL
case ma_backend_null:
{
Mc->callbacks.onContextInit=ma_context_init__null;
} break;
#endif
default:break;
}
if (Mc->callbacks.onContextInit !=NULL) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend));
Mf=Mc->callbacks.onContextInit(Mc,Mo,&Mc->callbacks);
} else {
if (backend !=ma_backend_custom) {
Mf=MA_BACKEND_NOT_ENABLED;
} else {
#if !defined(MA_HAS_CUSTOM)
Mf=MA_BACKEND_NOT_ENABLED;
#else
Mf=MA_NO_BACKEND;
#endif
}
}
if (Mf==Ms) {
Mf=ma_mutex_init(&Mc->deviceEnumLock);
if (Mf !=Ms) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.\n");
}
Mf=ma_mutex_init(&Mc->deviceInfoLock);
if (Mf !=Ms) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n");
}
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "System Architecture:\n");
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " Endian: %s\n", ma_is_little_endian() ? "LE" : "BE");
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " SSE2: %s\n", ma_has_sse2() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " AVX2: %s\n", ma_has_avx2() ? "YES" : "NO");
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, " NEON: %s\n", ma_has_neon() ? "YES" : "NO");
Mc->backend=backend;
Mr Mf;
} else {
if (Mf==MA_BACKEND_NOT_ENABLED) {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "%s backend is disabled.\n", ma_get_backend_name(backend));
} else {
ma_log_postf(ma_context_get_log(Mc), MA_LOG_LEVEL_DEBUG, "Failed to initialize %s backend.\n", ma_get_backend_name(backend));
}
}
}
MA_ZERO_OBJECT(Mc);
Mr MA_NO_BACKEND;
}
MA_API Me ma_context_uninit(ma_context*Mc)
{
if (Mc==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mc->callbacks.onContextUninit !=NULL) {
Mc->callbacks.onContextUninit(Mc);
}
ma_mutex_uninit(&Mc->deviceEnumLock);
ma_mutex_uninit(&Mc->deviceInfoLock);
ma_free(Mc->pDeviceInfos,&Mc->allocationCallbacks);
ma_context_uninit_backend_apis(Mc);
if (Mc->pLog==&Mc->log) {
ma_log_uninit(&Mc->log);
}
Mr Ms;
}
MA_API size_t ma_context_sizeof(Mv)
{
Mr sizeof(ma_context);
}
MA_API ma_log*ma_context_get_log(ma_context*Mc)
{
if (Mc==NULL) {
Mr NULL;
}
Mr Mc->pLog;
}
MA_API Me ma_context_enumerate_devices(ma_context*Mc,ma_enum_devices_callback_proc callback,Mv*pUserData)
{
Me Mf;
if (Mc==NULL||callback==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mc->callbacks.onContextEnumerateDevices==NULL) {
Mr MA_INVALID_OPERATION;
}
ma_mutex_lock(&Mc->deviceEnumLock);
{
Mf=Mc->callbacks.onContextEnumerateDevices(Mc,callback,pUserData);
}
ma_mutex_unlock(&Mc->deviceEnumLock);
Mr Mf;
}
static ma_bool32 ma_context_get_devices__enum_callback(ma_context*Mc,ma_device_type deviceType,const ma_device_info*pInfo,Mv*pUserData)
{
const M3 bufferExpansionCount=2;
const M3 totalDeviceInfoCount=Mc->playbackDeviceInfoCount+Mc->captureDeviceInfoCount;
if (totalDeviceInfoCount>=Mc->deviceInfoCapacity) {
M3 newCapacity=Mc->deviceInfoCapacity+bufferExpansionCount;
ma_device_info*pNewInfos=(ma_device_info*)ma_realloc(Mc->pDeviceInfos,sizeof(*Mc->pDeviceInfos)*newCapacity,&Mc->allocationCallbacks);
if (pNewInfos==NULL) {
Mr MA_FALSE;
}
Mc->pDeviceInfos=pNewInfos;
Mc->deviceInfoCapacity=newCapacity;
}
if (deviceType==Mt) {
M3 iFirstCaptureDevice=Mc->playbackDeviceInfoCount;
size_t iCaptureDevice;
for (iCaptureDevice=totalDeviceInfoCount; iCaptureDevice>iFirstCaptureDevice;--iCaptureDevice) {
Mc->pDeviceInfos[iCaptureDevice]=Mc->pDeviceInfos[iCaptureDevice-1];
}
Mc->pDeviceInfos[iFirstCaptureDevice]=*pInfo;
Mc->playbackDeviceInfoCount+=1;
} else {
Mc->pDeviceInfos[totalDeviceInfoCount]=*pInfo;
Mc->captureDeviceInfoCount+=1;
}
(Mv)pUserData;
Mr MA_TRUE;
}
MA_API Me ma_context_get_devices(ma_context*Mc,ma_device_info**ppPlaybackDeviceInfos,M3*pPlaybackDeviceCount,ma_device_info**ppCaptureDeviceInfos,M3*pCaptureDeviceCount)
{
Me Mf;
if (ppPlaybackDeviceInfos !=NULL)*ppPlaybackDeviceInfos=NULL;
if (pPlaybackDeviceCount !=NULL)*pPlaybackDeviceCount=0;
if (ppCaptureDeviceInfos !=NULL)*ppCaptureDeviceInfos=NULL;
if (pCaptureDeviceCount !=NULL)*pCaptureDeviceCount=0;
if (Mc==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mc->callbacks.onContextEnumerateDevices==NULL) {
Mr MA_INVALID_OPERATION;
}
ma_mutex_lock(&Mc->deviceEnumLock);
{
Mc->playbackDeviceInfoCount=0;
Mc->captureDeviceInfoCount=0;
Mf=Mc->callbacks.onContextEnumerateDevices(Mc,ma_context_get_devices__enum_callback,NULL);
if (Mf==Ms) {
if (ppPlaybackDeviceInfos !=NULL) {
*ppPlaybackDeviceInfos=Mc->pDeviceInfos;
}
if (pPlaybackDeviceCount !=NULL) {
*pPlaybackDeviceCount=Mc->playbackDeviceInfoCount;
}
if (ppCaptureDeviceInfos !=NULL) {
*ppCaptureDeviceInfos=Mc->pDeviceInfos;
if (Mc->playbackDeviceInfoCount>0) {
*ppCaptureDeviceInfos+=Mc->playbackDeviceInfoCount;
}
}
if (pCaptureDeviceCount !=NULL) {
*pCaptureDeviceCount=Mc->captureDeviceInfoCount;
}
}
}
ma_mutex_unlock(&Mc->deviceEnumLock);
Mr Mf;
}
MA_API Me ma_context_get_device_info(ma_context*Mc,ma_device_type deviceType,const ma_device_id*pDeviceID,ma_device_info*pDeviceInfo)
{
Me Mf;
ma_device_info deviceInfo;
if (Mc==NULL||pDeviceInfo==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(&deviceInfo);
if (pDeviceID !=NULL) {
MA_COPY_MEMORY(&deviceInfo.id,pDeviceID,sizeof(*pDeviceID));
}
if (Mc->callbacks.onContextGetDeviceInfo==NULL) {
Mr MA_INVALID_OPERATION;
}
ma_mutex_lock(&Mc->deviceInfoLock);
{
Mf=Mc->callbacks.onContextGetDeviceInfo(Mc,deviceType,pDeviceID,&deviceInfo);
}
ma_mutex_unlock(&Mc->deviceInfoLock);
*pDeviceInfo=deviceInfo;
Mr Mf;
}
MA_API ma_bool32 ma_context_is_loopback_supported(ma_context*Mc)
{
if (Mc==NULL) {
Mr MA_FALSE;
}
Mr ma_is_loopback_supported(Mc->backend);
}
MA_API ma_device_config ma_device_config_init(ma_device_type deviceType)
{
ma_device_config config;
MA_ZERO_OBJECT(&config);
config.deviceType=deviceType;
config.resampling=ma_resampler_config_init(ma_format_unknown,0,0,0,ma_resample_algorithm_linear);
Mr config;
}
MA_API Me ma_device_init(ma_context*Mc,const ma_device_config*Mo,ma_device*Md)
{
Me Mf;
ma_device_descriptor descriptorPlayback;
ma_device_descriptor descriptorCapture;
if (Mc==NULL) {
Mr ma_device_init_ex(NULL,0,NULL,Mo,Md);
}
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(Md);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mc->callbacks.onDeviceInit==NULL) {
Mr MA_INVALID_OPERATION;
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex) {
if (Mo->capture.Mh>MA_MAX_CHANNELS) {
Mr MA_INVALID_ARGS;
}
if (!ma__is_channel_map_valid(Mo->capture.pChannelMap,Mo->capture.Mh)) {
Mr MA_INVALID_ARGS;
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex||Mo->deviceType==ma_device_type_loopback) {
if (Mo->playback.Mh>MA_MAX_CHANNELS) {
Mr MA_INVALID_ARGS;
}
if (!ma__is_channel_map_valid(Mo->playback.pChannelMap,Mo->playback.Mh)) {
Mr MA_INVALID_ARGS;
}
}
Md->Mc=Mc;
Md->pUserData=Mo->pUserData;
Md->onData=Mo->dataCallback;
Md->onNotification=Mo->notificationCallback;
Md->onStop=Mo->stopCallback;
if (Mo->playback.pDeviceID !=NULL) {
MA_COPY_MEMORY(&Md->playback.id,Mo->playback.pDeviceID,sizeof(Md->playback.id));
Md->playback.pID=&Md->playback.id;
} else {
Md->playback.pID=NULL;
}
if (Mo->capture.pDeviceID !=NULL) {
MA_COPY_MEMORY(&Md->capture.id,Mo->capture.pDeviceID,sizeof(Md->capture.id));
Md->capture.pID=&Md->capture.id;
} else {
Md->capture.pID=NULL;
}
Md->noPreSilencedOutputBuffer=Mo->noPreSilencedOutputBuffer;
Md->noClip=Mo->noClip;
Md->noDisableDenormals=Mo->noDisableDenormals;
Md->noFixedSizedCallback=Mo->noFixedSizedCallback;
ma_atomic_float_set(&Md->masterVolumeFactor,1);
Md->type=Mo->deviceType;
Md->sampleRate=Mo->sampleRate;
Md->resampling.algorithm=Mo->resampling.algorithm;
Md->resampling.linear.lpfOrder=Mo->resampling.linear.lpfOrder;
Md->resampling.pBackendVTable=Mo->resampling.pBackendVTable;
Md->resampling.pBackendUserData=Mo->resampling.pBackendUserData;
Md->capture.shareMode=Mo->capture.shareMode;
Md->capture.format=Mo->capture.format;
Md->capture.Mh=Mo->capture.Mh;
ma_channel_map_copy_or_default(Md->capture.channelMap,ma_countof(Md->capture.channelMap),Mo->capture.pChannelMap,Mo->capture.Mh);
Md->capture.channelMixMode=Mo->capture.channelMixMode;
Md->capture.calculateLFEFromSpatialChannels=Mo->capture.calculateLFEFromSpatialChannels;
Md->playback.shareMode=Mo->playback.shareMode;
Md->playback.format=Mo->playback.format;
Md->playback.Mh=Mo->playback.Mh;
ma_channel_map_copy_or_default(Md->playback.channelMap,ma_countof(Md->playback.channelMap),Mo->playback.pChannelMap,Mo->playback.Mh);
Md->playback.channelMixMode=Mo->playback.channelMixMode;
Md->playback.calculateLFEFromSpatialChannels=Mo->playback.calculateLFEFromSpatialChannels;
Mf=ma_mutex_init(&Md->startStopLock);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_event_init(&Md->wakeupEvent);
if (Mf !=Ms) {
ma_mutex_uninit(&Md->startStopLock);
Mr Mf;
}
Mf=ma_event_init(&Md->startEvent);
if (Mf !=Ms) {
ma_event_uninit(&Md->wakeupEvent);
ma_mutex_uninit(&Md->startStopLock);
Mr Mf;
}
Mf=ma_event_init(&Md->stopEvent);
if (Mf !=Ms) {
ma_event_uninit(&Md->startEvent);
ma_event_uninit(&Md->wakeupEvent);
ma_mutex_uninit(&Md->startStopLock);
Mr Mf;
}
MA_ZERO_OBJECT(&descriptorPlayback);
descriptorPlayback.pDeviceID=Mo->playback.pDeviceID;
descriptorPlayback.shareMode=Mo->playback.shareMode;
descriptorPlayback.format=Mo->playback.format;
descriptorPlayback.Mh=Mo->playback.Mh;
descriptorPlayback.sampleRate=Mo->sampleRate;
ma_channel_map_copy_or_default(descriptorPlayback.channelMap,ma_countof(descriptorPlayback.channelMap),Mo->playback.pChannelMap,Mo->playback.Mh);
descriptorPlayback.periodSizeInFrames=Mo->periodSizeInFrames;
descriptorPlayback.periodSizeInMilliseconds=Mo->periodSizeInMilliseconds;
descriptorPlayback.periodCount=Mo->periods;
if (descriptorPlayback.periodCount==0) {
descriptorPlayback.periodCount=MA_DEFAULT_PERIODS;
}
MA_ZERO_OBJECT(&descriptorCapture);
descriptorCapture.pDeviceID=Mo->capture.pDeviceID;
descriptorCapture.shareMode=Mo->capture.shareMode;
descriptorCapture.format=Mo->capture.format;
descriptorCapture.Mh=Mo->capture.Mh;
descriptorCapture.sampleRate=Mo->sampleRate;
ma_channel_map_copy_or_default(descriptorCapture.channelMap,ma_countof(descriptorCapture.channelMap),Mo->capture.pChannelMap,Mo->capture.Mh);
descriptorCapture.periodSizeInFrames=Mo->periodSizeInFrames;
descriptorCapture.periodSizeInMilliseconds=Mo->periodSizeInMilliseconds;
descriptorCapture.periodCount=Mo->periods;
if (descriptorCapture.periodCount==0) {
descriptorCapture.periodCount=MA_DEFAULT_PERIODS;
}
Mf=Mc->callbacks.onDeviceInit(Md,Mo,&descriptorPlayback,&descriptorCapture);
if (Mf !=Ms) {
ma_event_uninit(&Md->startEvent);
ma_event_uninit(&Md->wakeupEvent);
ma_mutex_uninit(&Md->startStopLock);
Mr Mf;
}
#if 0
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex||Mo->deviceType==ma_device_type_loopback) {
if (!ma_device_descriptor_is_valid(&descriptorCapture)) {
ma_device_uninit(Md);
Mr MA_INVALID_ARGS;
}
Md->capture.internalFormat=descriptorCapture.format;
Md->capture.internalChannels=descriptorCapture.Mh;
Md->capture.internalSampleRate=descriptorCapture.sampleRate;
ma_channel_map_copy(Md->capture.internalChannelMap,descriptorCapture.channelMap,descriptorCapture.Mh);
Md->capture.internalPeriodSizeInFrames=descriptorCapture.periodSizeInFrames;
Md->capture.internalPeriods=descriptorCapture.periodCount;
if (Md->capture.internalPeriodSizeInFrames==0) {
Md->capture.internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorCapture.periodSizeInMilliseconds,descriptorCapture.sampleRate);
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
if (!ma_device_descriptor_is_valid(&descriptorPlayback)) {
ma_device_uninit(Md);
Mr MA_INVALID_ARGS;
}
Md->playback.internalFormat=descriptorPlayback.format;
Md->playback.internalChannels=descriptorPlayback.Mh;
Md->playback.internalSampleRate=descriptorPlayback.sampleRate;
ma_channel_map_copy(Md->playback.internalChannelMap,descriptorPlayback.channelMap,descriptorPlayback.Mh);
Md->playback.internalPeriodSizeInFrames=descriptorPlayback.periodSizeInFrames;
Md->playback.internalPeriods=descriptorPlayback.periodCount;
if (Md->playback.internalPeriodSizeInFrames==0) {
Md->playback.internalPeriodSizeInFrames=ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorPlayback.periodSizeInMilliseconds,descriptorPlayback.sampleRate);
}
}
{
ma_device_info deviceInfo;
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex||Mo->deviceType==ma_device_type_loopback) {
Mf=ma_device_get_info(Md,(Mo->deviceType==ma_device_type_loopback)?Mt:ma_device_type_capture,&deviceInfo);
if (Mf==Ms) {
ma_strncpy_s(Md->capture.name,sizeof(Md->capture.name),deviceInfo.name,(size_t)-1);
} else {
if (descriptorCapture.pDeviceID==NULL) {
 ma_strncpy_s(Md->capture.name,sizeof(Md->capture.name),MA_DEFAULT_CAPTURE_DEVICE_NAME,(size_t)-1);
} else {
 ma_strncpy_s(Md->capture.name, sizeof(Md->capture.name), "Capture Device", (size_t)-1);
}
}
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
Mf=ma_device_get_info(Md,Mt,&deviceInfo);
if (Mf==Ms) {
ma_strncpy_s(Md->playback.name,sizeof(Md->playback.name),deviceInfo.name,(size_t)-1);
} else {
if (descriptorPlayback.pDeviceID==NULL) {
 ma_strncpy_s(Md->playback.name,sizeof(Md->playback.name),MA_DEFAULT_PLAYBACK_DEVICE_NAME,(size_t)-1);
} else {
 ma_strncpy_s(Md->playback.name, sizeof(Md->playback.name), "Playback Device", (size_t)-1);
}
}
}
}
ma_device__post_init_setup(Md,Mo->deviceType);
#endif
Mf=ma_device_post_init(Md,Mo->deviceType,&descriptorPlayback,&descriptorCapture);
if (Mf !=Ms) {
ma_device_uninit(Md);
Mr Mf;
}
if (Mo->noFixedSizedCallback==MA_FALSE) {
M3 intermediaryBufferCap=Mo->periodSizeInFrames;
if (intermediaryBufferCap==0) {
intermediaryBufferCap=ma_calculate_buffer_size_in_frames_from_milliseconds(Mo->periodSizeInMilliseconds,Md->sampleRate);
}
if (Mo->deviceType==ma_device_type_capture||Mo->deviceType==ma_device_type_duplex||Mo->deviceType==ma_device_type_loopback) {
M3 intermediaryBufferSizeInBytes;
Md->capture.intermediaryBufferLen=0;
Md->capture.intermediaryBufferCap=intermediaryBufferCap;
if (Md->capture.intermediaryBufferCap==0) {
Md->capture.intermediaryBufferCap=Md->capture.internalPeriodSizeInFrames;
}
intermediaryBufferSizeInBytes=Md->capture.intermediaryBufferCap*ma_get_bytes_per_frame(Md->capture.format,Md->capture.Mh);
Md->capture.pIntermediaryBuffer=ma_malloc((size_t)intermediaryBufferSizeInBytes,&Mc->allocationCallbacks);
if (Md->capture.pIntermediaryBuffer==NULL) {
ma_device_uninit(Md);
Mr MA_OUT_OF_MEMORY;
}
ma_silence_pcm_frames(Md->capture.pIntermediaryBuffer,Md->capture.intermediaryBufferCap,Md->capture.format,Md->capture.Mh);
Md->capture.intermediaryBufferLen=Md->capture.intermediaryBufferCap;
}
if (Mo->deviceType==Mt||Mo->deviceType==ma_device_type_duplex) {
M6 intermediaryBufferSizeInBytes;
Md->playback.intermediaryBufferLen=0;
if (Mo->deviceType==ma_device_type_duplex) {
Md->playback.intermediaryBufferCap=Md->capture.intermediaryBufferCap;
} else {
Md->playback.intermediaryBufferCap=intermediaryBufferCap;
if (Md->playback.intermediaryBufferCap==0) {
 Md->playback.intermediaryBufferCap=Md->playback.internalPeriodSizeInFrames;
}
}
intermediaryBufferSizeInBytes=Md->playback.intermediaryBufferCap*ma_get_bytes_per_frame(Md->playback.format,Md->playback.Mh);
Md->playback.pIntermediaryBuffer=ma_malloc((size_t)intermediaryBufferSizeInBytes,&Mc->allocationCallbacks);
if (Md->playback.pIntermediaryBuffer==NULL) {
ma_device_uninit(Md);
Mr MA_OUT_OF_MEMORY;
}
ma_silence_pcm_frames(Md->playback.pIntermediaryBuffer,Md->playback.intermediaryBufferCap,Md->playback.format,Md->playback.Mh);
Md->playback.intermediaryBufferLen=0;
}
} else {
}
if (!ma_context_is_backend_asynchronous(Mc)) {
Mf=ma_thread_create(&Md->thread,Mc->threadPriority,Mc->threadStackSize,ma_worker_thread,Md,&Mc->allocationCallbacks);
if (Mf !=Ms) {
ma_device_uninit(Md);
Mr Mf;
}
ma_event_wait(&Md->stopEvent);
MA_ASSERT(ma_device_get_state(Md)==ma_device_state_stopped);
} else {
if (ma_context_is_backend_asynchronous(Mc)) {
if (Mo->deviceType==ma_device_type_duplex) {
Mf=ma_duplex_rb_init(Md->capture.format,Md->capture.Mh,Md->sampleRate,Md->capture.internalSampleRate,Md->capture.internalPeriodSizeInFrames,&Md->Mc->allocationCallbacks,&Md->duplexRB);
if (Mf !=Ms) {
 ma_device_uninit(Md);
 Mr Mf;
}
}
}
ma_device__set_state(Md,ma_device_state_stopped);
}
{
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(Md->Mc->backend));
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex||Md->type==ma_device_type_loopback) {
char name[MA_MAX_DEVICE_NAME_LENGTH+1];
ma_device_get_name(Md,ma_device_type_capture,name,sizeof(name),NULL);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Capture");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(Md->capture.internalFormat), ma_get_format_name(Md->capture.format));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", Md->capture.internalChannels, Md->capture.Mh);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", Md->capture.internalSampleRate, Md->sampleRate);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", Md->capture.internalPeriodSizeInFrames, Md->capture.internalPeriods, (Md->capture.internalPeriodSizeInFrames * Md->capture.internalPeriods));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Conversion:\n");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", Md->capture.converter.hasPreFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", Md->capture.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", Md->capture.converter.hasChannelConverter ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Resampling: %s\n", Md->capture.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", Md->capture.converter.isPassthrough ? "YES" : "NO");
{
char channelMapStr[1024];
ma_channel_map_to_string(Md->capture.internalChannelMap,Md->capture.internalChannels,channelMapStr,sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}\n", channelMapStr);
ma_channel_map_to_string(Md->capture.channelMap,Md->capture.Mh,channelMapStr,sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}\n", channelMapStr);
}
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
char name[MA_MAX_DEVICE_NAME_LENGTH+1];
ma_device_get_name(Md,Mt,name,sizeof(name),NULL);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Playback");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(Md->playback.format), ma_get_format_name(Md->playback.internalFormat));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channels: %d -> %d\n", Md->playback.Mh, Md->playback.internalChannels);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d\n", Md->sampleRate, Md->playback.internalSampleRate);
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)\n", Md->playback.internalPeriodSizeInFrames, Md->playback.internalPeriods, (Md->playback.internalPeriodSizeInFrames * Md->playback.internalPeriods));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Conversion:\n");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s\n", Md->playback.converter.hasPreFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Post Format Conversion: %s\n", Md->playback.converter.hasPostFormatConversion ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channel Routing: %s\n", Md->playback.converter.hasChannelConverter ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Resampling: %s\n", Md->playback.converter.hasResampler ? "YES" : "NO");
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Passthrough: %s\n", Md->playback.converter.isPassthrough ? "YES" : "NO");
{
char channelMapStr[1024];
ma_channel_map_to_string(Md->playback.channelMap,Md->playback.Mh,channelMapStr,sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channel Map In: {%s}\n", channelMapStr);
ma_channel_map_to_string(Md->playback.internalChannelMap,Md->playback.internalChannels,channelMapStr,sizeof(channelMapStr));
ma_log_postf(ma_device_get_log(Md), MA_LOG_LEVEL_INFO, " Channel Map Out: {%s}\n", channelMapStr);
}
}
}
MA_ASSERT(ma_device_get_state(Md)==ma_device_state_stopped);
Mr Ms;
}
MA_API Me ma_device_init_ex(const ma_backend backends[],M3 backendCount,const ma_context_config*pContextConfig,const ma_device_config*Mo,ma_device*Md)
{
Me Mf;
ma_context*Mc;
ma_backend defaultBackends[ma_backend_null+1];
M3 iBackend;
ma_backend*pBackendsToIterate;
M3 backendsToIterateCount;
ma_allocation_callbacks allocationCallbacks;
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (pContextConfig !=NULL) {
Mf=ma_allocation_callbacks_init_copy(&allocationCallbacks,&pContextConfig->allocationCallbacks);
if (Mf !=Ms) {
Mr Mf;
}
} else {
allocationCallbacks=ma_allocation_callbacks_init_default();
}
Mc=(ma_context*)ma_malloc(sizeof(*Mc),&allocationCallbacks);
if (Mc==NULL) {
Mr MA_OUT_OF_MEMORY;
}
for (iBackend=0; iBackend<=ma_backend_null;++iBackend) {
defaultBackends[iBackend]=(ma_backend)iBackend;
}
pBackendsToIterate=(ma_backend*)backends;
backendsToIterateCount=backendCount;
if (pBackendsToIterate==NULL) {
pBackendsToIterate=(ma_backend*)defaultBackends;
backendsToIterateCount=ma_countof(defaultBackends);
}
Mf=MA_NO_BACKEND;
for (iBackend=0; iBackend<backendsToIterateCount;++iBackend) {
#if defined(MA_APPLE_MOBILE)
ma_context_config contextConfig;
if (pContextConfig==NULL) {
contextConfig=ma_context_config_init();
switch (Mo->deviceType) {
case ma_device_type_duplex:{
 contextConfig.coreaudio.sessionCategory=ma_ios_session_category_play_and_record;
} break;
case ma_device_type_capture:{
 contextConfig.coreaudio.sessionCategory=ma_ios_session_category_record;
} break;
case Mt:
default:{
 contextConfig.coreaudio.sessionCategory=ma_ios_session_category_playback;
} break;
}
pContextConfig=&contextConfig;
}
#endif
Mf=ma_context_init(&pBackendsToIterate[iBackend],1,pContextConfig,Mc);
if (Mf==Ms) {
Mf=ma_device_init(Mc,Mo,Md);
if (Mf==Ms) {
break;
} else {
ma_context_uninit(Mc);
}
}
}
if (Mf !=Ms) {
ma_free(Mc,&allocationCallbacks);
Mr Mf;
}
Md->isOwnerOfContext=MA_TRUE;
Mr Mf;
}
MA_API Mv ma_device_uninit(ma_device*Md)
{
if (!ma_device__is_initialized(Md)) {
Mr;
}
#if 0
{
if (ma_device_is_started(Md)) {
ma_device_stop(Md);
}
}
#endif
ma_device__set_state(Md,ma_device_state_uninitialized);
if (!ma_context_is_backend_asynchronous(Md->Mc)) {
ma_event_signal(&Md->wakeupEvent);
ma_thread_wait(&Md->thread);
}
if (Md->Mc->callbacks.onDeviceUninit !=NULL) {
Md->Mc->callbacks.onDeviceUninit(Md);
}
ma_event_uninit(&Md->stopEvent);
ma_event_uninit(&Md->startEvent);
ma_event_uninit(&Md->wakeupEvent);
ma_mutex_uninit(&Md->startStopLock);
if (ma_context_is_backend_asynchronous(Md->Mc)) {
if (Md->type==ma_device_type_duplex) {
ma_duplex_rb_uninit(&Md->duplexRB);
}
}
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_duplex||Md->type==ma_device_type_loopback) {
ma_data_converter_uninit(&Md->capture.converter,&Md->Mc->allocationCallbacks);
}
if (Md->type==Mt||Md->type==ma_device_type_duplex) {
ma_data_converter_uninit(&Md->playback.converter,&Md->Mc->allocationCallbacks);
}
if (Md->playback.pInputCache !=NULL) {
ma_free(Md->playback.pInputCache,&Md->Mc->allocationCallbacks);
}
if (Md->capture.pIntermediaryBuffer !=NULL) {
ma_free(Md->capture.pIntermediaryBuffer,&Md->Mc->allocationCallbacks);
}
if (Md->playback.pIntermediaryBuffer !=NULL) {
ma_free(Md->playback.pIntermediaryBuffer,&Md->Mc->allocationCallbacks);
}
if (Md->isOwnerOfContext) {
ma_allocation_callbacks allocationCallbacks=Md->Mc->allocationCallbacks;
ma_context_uninit(Md->Mc);
ma_free(Md->Mc,&allocationCallbacks);
}
MA_ZERO_OBJECT(Md);
}
MA_API ma_context*ma_device_get_context(ma_device*Md)
{
if (Md==NULL) {
Mr NULL;
}
Mr Md->Mc;
}
MA_API ma_log*ma_device_get_log(ma_device*Md)
{
Mr ma_context_get_log(ma_device_get_context(Md));
}
MA_API Me ma_device_get_info(ma_device*Md,ma_device_type type,ma_device_info*pDeviceInfo)
{
if (pDeviceInfo==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pDeviceInfo);
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
if (Md->Mc->callbacks.onDeviceGetInfo !=NULL) {
Mr Md->Mc->callbacks.onDeviceGetInfo(Md,type,pDeviceInfo);
}
if (type==Mt) {
Mr ma_context_get_device_info(Md->Mc,type,Md->playback.pID,pDeviceInfo);
} else {
if (Md->type==ma_device_type_loopback&&Md->capture.pID==NULL) {
type=Mt;
}
Mr ma_context_get_device_info(Md->Mc,type,Md->capture.pID,pDeviceInfo);
}
}
MA_API Me ma_device_get_name(ma_device*Md,ma_device_type type,char*pName,size_t nameCap,size_t*pLengthNotIncludingNullTerminator)
{
Me Mf;
ma_device_info deviceInfo;
if (pLengthNotIncludingNullTerminator !=NULL) {
*pLengthNotIncludingNullTerminator=0;
}
if (pName !=NULL&&nameCap>0) {
pName[0]='\0';
}
Mf=ma_device_get_info(Md,type,&deviceInfo);
if (Mf !=Ms) {
Mr Mf;
}
if (pName !=NULL) {
ma_strncpy_s(pName,nameCap,deviceInfo.name,(size_t)-1);
if (pLengthNotIncludingNullTerminator !=NULL) {
*pLengthNotIncludingNullTerminator=strlen(pName);
}
} else {
if (pLengthNotIncludingNullTerminator !=NULL) {
*pLengthNotIncludingNullTerminator=strlen(deviceInfo.name);
}
}
Mr Ms;
}
MA_API Me ma_device_start(ma_device*Md)
{
Me Mf;
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
if (ma_device_get_state(Md)==ma_device_state_uninitialized) {
Mr MA_INVALID_OPERATION;
}
if (ma_device_get_state(Md)==ma_device_state_started) {
Mr Ms;
}
ma_mutex_lock(&Md->startStopLock);
{
if (ma_device_get_state(Md)==ma_device_state_started) {
ma_mutex_unlock(&Md->startStopLock);
Mr Ms;
}
MA_ASSERT(ma_device_get_state(Md)==ma_device_state_stopped);
ma_device__set_state(Md,ma_device_state_starting);
if (ma_context_is_backend_asynchronous(Md->Mc)) {
if (Md->Mc->callbacks.onDeviceStart !=NULL) {
Mf=Md->Mc->callbacks.onDeviceStart(Md);
} else {
Mf=MA_INVALID_OPERATION;
}
if (Mf==Ms) {
ma_device__set_state(Md,ma_device_state_started);
ma_device__on_notification_started(Md);
}
} else {
ma_event_signal(&Md->wakeupEvent);
ma_event_wait(&Md->startEvent);
Mf=Md->workResult;
}
if (Mf !=Ms) {
ma_device__set_state(Md,ma_device_state_stopped);
}
}
ma_mutex_unlock(&Md->startStopLock);
Mr Mf;
}
MA_API Me ma_device_stop(ma_device*Md)
{
Me Mf;
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
if (ma_device_get_state(Md)==ma_device_state_uninitialized) {
Mr MA_INVALID_OPERATION;
}
if (ma_device_get_state(Md)==ma_device_state_stopped) {
Mr Ms;
}
ma_mutex_lock(&Md->startStopLock);
{
if (ma_device_get_state(Md)==ma_device_state_stopped) {
ma_mutex_unlock(&Md->startStopLock);
Mr Ms;
}
MA_ASSERT(ma_device_get_state(Md)==ma_device_state_started);
ma_device__set_state(Md,ma_device_state_stopping);
if (ma_context_is_backend_asynchronous(Md->Mc)) {
if (Md->Mc->callbacks.onDeviceStop !=NULL) {
Mf=Md->Mc->callbacks.onDeviceStop(Md);
} else {
Mf=MA_INVALID_OPERATION;
}
ma_device__set_state(Md,ma_device_state_stopped);
} else {
MA_ASSERT(ma_device_get_state(Md) !=ma_device_state_started);
if (Md->Mc->callbacks.onDeviceDataLoopWakeup !=NULL) {
Md->Mc->callbacks.onDeviceDataLoopWakeup(Md);
}
ma_event_wait(&Md->stopEvent);
Mf=Ms;
}
Md->playback.intermediaryBufferLen=0;
Md->playback.inputCacheConsumed=0;
Md->playback.inputCacheRemaining=0;
}
ma_mutex_unlock(&Md->startStopLock);
Mr Mf;
}
MA_API ma_bool32 ma_device_is_started(const ma_device*Md)
{
Mr ma_device_get_state(Md)==ma_device_state_started;
}
MA_API ma_device_state ma_device_get_state(const ma_device*Md)
{
if (Md==NULL) {
Mr ma_device_state_uninitialized;
}
Mr ma_atomic_device_state_get((ma_atomic_device_state*)&Md->state);
}
MA_API Me ma_device_set_master_volume(ma_device*Md,float volume)
{
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
if (volume<0.0f) {
Mr MA_INVALID_ARGS;
}
ma_atomic_float_set(&Md->masterVolumeFactor,volume);
Mr Ms;
}
MA_API Me ma_device_get_master_volume(ma_device*Md,float*pVolume)
{
if (pVolume==NULL) {
Mr MA_INVALID_ARGS;
}
if (Md==NULL) {
*pVolume=0;
Mr MA_INVALID_ARGS;
}
*pVolume=ma_atomic_float_get(&Md->masterVolumeFactor);
Mr Ms;
}
MA_API Me ma_device_set_master_volume_db(ma_device*Md,float gainDB)
{
if (gainDB>0) {
Mr MA_INVALID_ARGS;
}
Mr ma_device_set_master_volume(Md,ma_volume_db_to_linear(gainDB));
}
MA_API Me ma_device_get_master_volume_db(ma_device*Md,float*pGainDB)
{
float factor;
Me Mf;
if (pGainDB==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_device_get_master_volume(Md,&factor);
if (Mf !=Ms) {
*pGainDB=0;
Mr Mf;
}
*pGainDB=ma_volume_linear_to_db(factor);
Mr Ms;
}
MA_API Me ma_device_handle_backend_data_callback(ma_device*Md,Mv*pOutput,const Mv*pInput,M3 frameCount)
{
if (Md==NULL) {
Mr MA_INVALID_ARGS;
}
if (pOutput==NULL&&pInput==NULL) {
Mr MA_INVALID_ARGS;
}
if (frameCount==0) {
Mr MA_INVALID_ARGS;
}
if (Md->type==ma_device_type_duplex) {
if (pInput !=NULL) {
ma_device__handle_duplex_callback_capture(Md,frameCount,pInput,&Md->duplexRB.rb);
}
if (pOutput !=NULL) {
ma_device__handle_duplex_callback_playback(Md,frameCount,pOutput,&Md->duplexRB.rb);
}
} else {
if (Md->type==ma_device_type_capture||Md->type==ma_device_type_loopback) {
if (pInput==NULL) {
Mr MA_INVALID_ARGS;
}
ma_device__send_frames_to_client(Md,frameCount,pInput);
}
if (Md->type==Mt) {
if (pOutput==NULL) {
Mr MA_INVALID_ARGS;
}
ma_device__read_frames_from_client(Md,frameCount,pOutput);
}
}
Mr Ms;
}
MA_API M3 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor*pDescriptor,M3 nativeSampleRate,ma_performance_profile performanceProfile)
{
if (pDescriptor==NULL) {
Mr 0;
}
if (nativeSampleRate==0) {
nativeSampleRate=pDescriptor->sampleRate;
}
if (nativeSampleRate==0) {
nativeSampleRate=MA_DEFAULT_SAMPLE_RATE;
}
MA_ASSERT(nativeSampleRate !=0);
if (pDescriptor->periodSizeInFrames==0) {
if (pDescriptor->periodSizeInMilliseconds==0) {
if (performanceProfile==ma_performance_profile_low_latency) {
Mr ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY,nativeSampleRate);
} else {
Mr ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE,nativeSampleRate);
}
} else {
Mr ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds,nativeSampleRate);
}
} else {
Mr pDescriptor->periodSizeInFrames;
}
}
#endif
MA_API M3 ma_calculate_buffer_size_in_milliseconds_from_frames(M3 bufferSizeInFrames,M3 sampleRate)
{
if (sampleRate==0) {
Mr 0;
}
Mr (bufferSizeInFrames*1000+(sampleRate-1)) / sampleRate;
}
MA_API M3 ma_calculate_buffer_size_in_frames_from_milliseconds(M3 bufferSizeInMilliseconds,M3 sampleRate)
{
if (sampleRate==0) {
Mr 0;
}
Mr bufferSizeInMilliseconds*sampleRate / 1000;
}
MA_API Mv ma_copy_pcm_frames(Mv*dst,const Mv*src,M6 frameCount,ma_format format,M3 Mh)
{
if (dst==src) {
Mr;
}
ma_copy_memory_64(dst,src,frameCount*ma_get_bytes_per_frame(format,Mh));
}
MA_API Mv ma_silence_pcm_frames(Mv*p,M6 frameCount,ma_format format,M3 Mh)
{
if (format==ma_format_u8) {
M6 sampleCount=frameCount*Mh;
M6 iSample;
for (iSample=0; iSample<sampleCount; iSample+=1) {
((ma_uint8*)p)[iSample]=128;
}
} else {
ma_zero_memory_64(p,frameCount*ma_get_bytes_per_frame(format,Mh));
}
}
MA_API Mv*ma_offset_pcm_frames_ptr(Mv*p,M6 offsetInFrames,ma_format format,M3 Mh)
{
Mr ma_offset_ptr(p,offsetInFrames*ma_get_bytes_per_frame(format,Mh));
}
MA_API const Mv*ma_offset_pcm_frames_const_ptr(const Mv*p,M6 offsetInFrames,ma_format format,M3 Mh)
{
Mr ma_offset_ptr(p,offsetInFrames*ma_get_bytes_per_frame(format,Mh));
}
MA_API Mv ma_clip_samples_u8(ma_uint8*pDst,const ma_int16*pSrc,M6 count)
{
M6 iSample;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_u8(pSrc[iSample]);
}
}
MA_API Mv ma_clip_samples_s16(ma_int16*pDst,const ma_int32*pSrc,M6 count)
{
M6 iSample;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_s16(pSrc[iSample]);
}
}
MA_API Mv ma_clip_samples_s24(ma_uint8*pDst,const ma_int64*pSrc,M6 count)
{
M6 iSample;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
for (iSample=0; iSample<count; iSample+=1) {
ma_int64 s=ma_clip_s24(pSrc[iSample]);
pDst[iSample*3+0]=(ma_uint8)((s&0x000000FF)>>0);
pDst[iSample*3+1]=(ma_uint8)((s&0x0000FF00)>>8);
pDst[iSample*3+2]=(ma_uint8)((s&0x00FF0000)>>16);
}
}
MA_API Mv ma_clip_samples_s32(ma_int32*pDst,const ma_int64*pSrc,M6 count)
{
M6 iSample;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_s32(pSrc[iSample]);
}
}
MA_API Mv ma_clip_samples_f32(float*pDst,const float*pSrc,M6 count)
{
M6 iSample;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_f32(pSrc[iSample]);
}
}
MA_API Mv ma_clip_pcm_frames(Mv*pDst,const Mv*pSrc,M6 frameCount,ma_format format,M3 Mh)
{
M6 sampleCount;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
sampleCount=frameCount*Mh;
switch (format) {
case ma_format_u8:ma_clip_samples_u8( (ma_uint8*)pDst,(const ma_int16*)pSrc,sampleCount); break;
case ma_format_s16:ma_clip_samples_s16((ma_int16*)pDst,(const ma_int32*)pSrc,sampleCount); break;
case ma_format_s24:ma_clip_samples_s24((ma_uint8*)pDst,(const ma_int64*)pSrc,sampleCount); break;
case ma_format_s32:ma_clip_samples_s32((ma_int32*)pDst,(const ma_int64*)pSrc,sampleCount); break;
case ma_format_f32:ma_clip_samples_f32(( float*)pDst,(const float*)pSrc,sampleCount); break;
case ma_format_unknown:
case ma_format_count:
break;
}
}
MA_API Mv ma_copy_and_apply_volume_factor_u8(ma_uint8*pSamplesOut,const ma_uint8*pSamplesIn,M6 sampleCount,float factor)
{
M6 iSample;
if (pSamplesOut==NULL||pSamplesIn==NULL) {
Mr;
}
for (iSample=0; iSample<sampleCount; iSample+=1) {
pSamplesOut[iSample]=(ma_uint8)(pSamplesIn[iSample]*factor);
}
}
MA_API Mv ma_copy_and_apply_volume_factor_s16(ma_int16*pSamplesOut,const ma_int16*pSamplesIn,M6 sampleCount,float factor)
{
M6 iSample;
if (pSamplesOut==NULL||pSamplesIn==NULL) {
Mr;
}
for (iSample=0; iSample<sampleCount; iSample+=1) {
pSamplesOut[iSample]=(ma_int16)(pSamplesIn[iSample]*factor);
}
}
MA_API Mv ma_copy_and_apply_volume_factor_s24(Mv*pSamplesOut,const Mv*pSamplesIn,M6 sampleCount,float factor)
{
M6 iSample;
ma_uint8*pSamplesOut8;
ma_uint8*pSamplesIn8;
if (pSamplesOut==NULL||pSamplesIn==NULL) {
Mr;
}
pSamplesOut8=(ma_uint8*)pSamplesOut;
pSamplesIn8=(ma_uint8*)pSamplesIn;
for (iSample=0; iSample<sampleCount; iSample+=1) {
ma_int32 sampleS32;
sampleS32=(ma_int32)(((M3)(pSamplesIn8[iSample*3+0])<<8)|((M3)(pSamplesIn8[iSample*3+1])<<16)|((M3)(pSamplesIn8[iSample*3+2]))<<24);
sampleS32=(ma_int32)(sampleS32*factor);
pSamplesOut8[iSample*3+0]=(ma_uint8)(((M3)sampleS32&0x0000FF00)>>8);
pSamplesOut8[iSample*3+1]=(ma_uint8)(((M3)sampleS32&0x00FF0000)>>16);
pSamplesOut8[iSample*3+2]=(ma_uint8)(((M3)sampleS32&0xFF000000)>>24);
}
}
MA_API Mv ma_copy_and_apply_volume_factor_s32(ma_int32*pSamplesOut,const ma_int32*pSamplesIn,M6 sampleCount,float factor)
{
M6 iSample;
if (pSamplesOut==NULL||pSamplesIn==NULL) {
Mr;
}
for (iSample=0; iSample<sampleCount; iSample+=1) {
pSamplesOut[iSample]=(ma_int32)(pSamplesIn[iSample]*factor);
}
}
MA_API Mv ma_copy_and_apply_volume_factor_f32(float*pSamplesOut,const float*pSamplesIn,M6 sampleCount,float factor)
{
M6 iSample;
if (pSamplesOut==NULL||pSamplesIn==NULL) {
Mr;
}
if (factor==1) {
if (pSamplesOut==pSamplesIn) {
} else {
for (iSample=0; iSample<sampleCount; iSample+=1) {
pSamplesOut[iSample]=pSamplesIn[iSample];
}
}
} else {
for (iSample=0; iSample<sampleCount; iSample+=1) {
pSamplesOut[iSample]=pSamplesIn[iSample]*factor;
}
}
}
MA_API Mv ma_apply_volume_factor_u8(ma_uint8*pSamples,M6 sampleCount,float factor)
{
ma_copy_and_apply_volume_factor_u8(pSamples,pSamples,sampleCount,factor);
}
MA_API Mv ma_apply_volume_factor_s16(ma_int16*pSamples,M6 sampleCount,float factor)
{
ma_copy_and_apply_volume_factor_s16(pSamples,pSamples,sampleCount,factor);
}
MA_API Mv ma_apply_volume_factor_s24(Mv*pSamples,M6 sampleCount,float factor)
{
ma_copy_and_apply_volume_factor_s24(pSamples,pSamples,sampleCount,factor);
}
MA_API Mv ma_apply_volume_factor_s32(ma_int32*pSamples,M6 sampleCount,float factor)
{
ma_copy_and_apply_volume_factor_s32(pSamples,pSamples,sampleCount,factor);
}
MA_API Mv ma_apply_volume_factor_f32(float*pSamples,M6 sampleCount,float factor)
{
ma_copy_and_apply_volume_factor_f32(pSamples,pSamples,sampleCount,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8*pFramesOut,const ma_uint8*pFramesIn,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_u8(pFramesOut,pFramesIn,frameCount*Mh,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16*pFramesOut,const ma_int16*pFramesIn,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_s16(pFramesOut,pFramesIn,frameCount*Mh,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_s24(Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_s24(pFramesOut,pFramesIn,frameCount*Mh,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32*pFramesOut,const ma_int32*pFramesIn,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_s32(pFramesOut,pFramesIn,frameCount*Mh,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames_f32(float*pFramesOut,const float*pFramesIn,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_f32(pFramesOut,pFramesIn,frameCount*Mh,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_pcm_frames(Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount,ma_format format,M3 Mh,float factor)
{
switch (format)
{
case ma_format_u8:ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pFramesOut,(const ma_uint8*)pFramesIn,frameCount,Mh,factor); Mr;
case ma_format_s16:ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pFramesOut,(const ma_int16*)pFramesIn,frameCount,Mh,factor); Mr;
case ma_format_s24:ma_copy_and_apply_volume_factor_pcm_frames_s24( pFramesOut,pFramesIn,frameCount,Mh,factor); Mr;
case ma_format_s32:ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pFramesOut,(const ma_int32*)pFramesIn,frameCount,Mh,factor); Mr;
case ma_format_f32:ma_copy_and_apply_volume_factor_pcm_frames_f32( (float*)pFramesOut,(const float*)pFramesIn,frameCount,Mh,factor); Mr;
default:Mr;
}
}
MA_API Mv ma_apply_volume_factor_pcm_frames_u8(ma_uint8*pFrames,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_pcm_frames_u8(pFrames,pFrames,frameCount,Mh,factor);
}
MA_API Mv ma_apply_volume_factor_pcm_frames_s16(ma_int16*pFrames,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_pcm_frames_s16(pFrames,pFrames,frameCount,Mh,factor);
}
MA_API Mv ma_apply_volume_factor_pcm_frames_s24(Mv*pFrames,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_pcm_frames_s24(pFrames,pFrames,frameCount,Mh,factor);
}
MA_API Mv ma_apply_volume_factor_pcm_frames_s32(ma_int32*pFrames,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_pcm_frames_s32(pFrames,pFrames,frameCount,Mh,factor);
}
MA_API Mv ma_apply_volume_factor_pcm_frames_f32(float*pFrames,M6 frameCount,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_pcm_frames_f32(pFrames,pFrames,frameCount,Mh,factor);
}
MA_API Mv ma_apply_volume_factor_pcm_frames(Mv*pFramesOut,M6 frameCount,ma_format format,M3 Mh,float factor)
{
ma_copy_and_apply_volume_factor_pcm_frames(pFramesOut,pFramesOut,frameCount,format,Mh,factor);
}
MA_API Mv ma_copy_and_apply_volume_factor_per_channel_f32(float*pFramesOut,const float*pFramesIn,M6 frameCount,M3 Mh,float*pChannelGains)
{
M6 iFrame;
if (Mh==2) {
}
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
pFramesOut[iFrame*Mh+iChannel]=pFramesIn[iFrame*Mh+iChannel]*pChannelGains[iChannel];
}
}
}
static MA_INLINE ma_int16 ma_apply_volume_unclipped_u8(ma_int16 x,ma_int16 volume)
{
Mr (ma_int16)(((ma_int32)x*(ma_int32)volume)>>8);
}
static MA_INLINE ma_int32 ma_apply_volume_unclipped_s16(ma_int32 x,ma_int16 volume)
{
Mr (ma_int32)((x*volume)>>8);
}
static MA_INLINE ma_int64 ma_apply_volume_unclipped_s24(ma_int64 x,ma_int16 volume)
{
Mr (ma_int64)((x*volume)>>8);
}
static MA_INLINE ma_int64 ma_apply_volume_unclipped_s32(ma_int64 x,ma_int16 volume)
{
Mr (ma_int64)((x*volume)>>8);
}
static MA_INLINE float ma_apply_volume_unclipped_f32(float x,float volume)
{
Mr x*volume;
}
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8*pDst,const ma_int16*pSrc,M6 count,float volume)
{
M6 iSample;
ma_int16 volumeFixed;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
volumeFixed=ma_float_to_fixed_16(volume);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_u8(ma_apply_volume_unclipped_u8(pSrc[iSample],volumeFixed));
}
}
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16*pDst,const ma_int32*pSrc,M6 count,float volume)
{
M6 iSample;
ma_int16 volumeFixed;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
volumeFixed=ma_float_to_fixed_16(volume);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_s16(ma_apply_volume_unclipped_s16(pSrc[iSample],volumeFixed));
}
}
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8*pDst,const ma_int64*pSrc,M6 count,float volume)
{
M6 iSample;
ma_int16 volumeFixed;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
volumeFixed=ma_float_to_fixed_16(volume);
for (iSample=0; iSample<count; iSample+=1) {
ma_int64 s=ma_clip_s24(ma_apply_volume_unclipped_s24(pSrc[iSample],volumeFixed));
pDst[iSample*3+0]=(ma_uint8)((s&0x000000FF)>>0);
pDst[iSample*3+1]=(ma_uint8)((s&0x0000FF00)>>8);
pDst[iSample*3+2]=(ma_uint8)((s&0x00FF0000)>>16);
}
}
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32*pDst,const ma_int64*pSrc,M6 count,float volume)
{
M6 iSample;
ma_int16 volumeFixed;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
volumeFixed=ma_float_to_fixed_16(volume);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_s32(ma_apply_volume_unclipped_s32(pSrc[iSample],volumeFixed));
}
}
MA_API Mv ma_copy_and_apply_volume_and_clip_samples_f32(float*pDst,const float*pSrc,M6 count,float volume)
{
M6 iSample;
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
for (iSample=0; iSample<count; iSample+=1) {
pDst[iSample]=ma_clip_f32(ma_apply_volume_unclipped_f32(pSrc[iSample],volume));
}
}
MA_API Mv ma_copy_and_apply_volume_and_clip_pcm_frames(Mv*pDst,const Mv*pSrc,M6 frameCount,ma_format format,M3 Mh,float volume)
{
MA_ASSERT(pDst !=NULL);
MA_ASSERT(pSrc !=NULL);
if (volume==1) {
ma_clip_pcm_frames(pDst,pSrc,frameCount,format,Mh);
} else if (volume==0) {
ma_silence_pcm_frames(pDst,frameCount,format,Mh);
} else {
M6 sampleCount=frameCount*Mh;
switch (format) {
case ma_format_u8:ma_copy_and_apply_volume_and_clip_samples_u8( (ma_uint8*)pDst,(const ma_int16*)pSrc,sampleCount,volume); break;
case ma_format_s16:ma_copy_and_apply_volume_and_clip_samples_s16((ma_int16*)pDst,(const ma_int32*)pSrc,sampleCount,volume); break;
case ma_format_s24:ma_copy_and_apply_volume_and_clip_samples_s24((ma_uint8*)pDst,(const ma_int64*)pSrc,sampleCount,volume); break;
case ma_format_s32:ma_copy_and_apply_volume_and_clip_samples_s32((ma_int32*)pDst,(const ma_int64*)pSrc,sampleCount,volume); break;
case ma_format_f32:ma_copy_and_apply_volume_and_clip_samples_f32(( float*)pDst,(const float*)pSrc,sampleCount,volume); break;
case ma_format_unknown:
case ma_format_count:
break;
}
}
}
MA_API float ma_volume_linear_to_db(float factor)
{
Mr 20*ma_log10f(factor);
}
MA_API float ma_volume_db_to_linear(float gain)
{
Mr ma_powf(10,gain/20.0f);
}
MA_API Me ma_mix_pcm_frames_f32(float*pDst,const float*pSrc,M6 frameCount,M3 Mh,float volume)
{
M6 iSample;
M6 sampleCount;
if (pDst==NULL||pSrc==NULL||Mh==0) {
Mr MA_INVALID_ARGS;
}
if (volume==0) {
Mr Ms;
}
sampleCount=frameCount*Mh;
if (volume==1) {
for (iSample=0; iSample<sampleCount; iSample+=1) {
pDst[iSample]+=pSrc[iSample];
}
} else {
for (iSample=0; iSample<sampleCount; iSample+=1) {
pDst[iSample]+=ma_apply_volume_unclipped_f32(pSrc[iSample],volume);
}
}
Mr Ms;
}
static MA_INLINE ma_int16 ma_pcm_sample_f32_to_s16(float x)
{
Mr (ma_int16)(x*32767.0f);
}
static MA_INLINE ma_int16 ma_pcm_sample_u8_to_s16_no_scale(ma_uint8 x)
{
Mr (ma_int16)((ma_int16)x-128);
}
static MA_INLINE ma_int64 ma_pcm_sample_s24_to_s32_no_scale(const ma_uint8*x)
{
Mr (ma_int64)(((M6)x[0]<<40)|((M6)x[1]<<48)|((M6)x[2]<<56))>>40;
}
static MA_INLINE Mv ma_pcm_sample_s32_to_s24_no_scale(ma_int64 x,ma_uint8*s24)
{
s24[0]=(ma_uint8)((x&0x000000FF)>>0);
s24[1]=(ma_uint8)((x&0x0000FF00)>>8);
s24[2]=(ma_uint8)((x&0x00FF0000)>>16);
}
MA_API Mv ma_pcm_u8_to_u8(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
(Mv)ditherMode;
ma_copy_memory_64(dst,src,count*sizeof(ma_uint8));
}
static MA_INLINE Mv ma_pcm_u8_to_s16__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int16*dst_s16=(ma_int16*)dst;
const ma_uint8*src_u8=(const ma_uint8*)src;
M6 i;
for (i=0; i<count; i+=1) {
ma_int16 x=src_u8[i];
x=(ma_int16)(x-128);
x=(ma_int16)(x<<8);
dst_s16[i]=x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_u8_to_s16__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s16__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_u8_to_s16__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_u8_to_s16__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_u8_to_s16(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_u8_to_s16__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_u8_to_s16__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_u8_to_s16__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_u8_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_u8_to_s24__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_s24=(ma_uint8*)dst;
const ma_uint8*src_u8=(const ma_uint8*)src;
M6 i;
for (i=0; i<count; i+=1) {
ma_int16 x=src_u8[i];
x=(ma_int16)(x-128);
dst_s24[i*3+0]=0;
dst_s24[i*3+1]=0;
dst_s24[i*3+2]=(ma_uint8)((ma_int8)x);
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_u8_to_s24__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s24__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_u8_to_s24__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_u8_to_s24__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_u8_to_s24(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_u8_to_s24__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_u8_to_s24__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_u8_to_s24__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_u8_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_u8_to_s32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int32*dst_s32=(ma_int32*)dst;
const ma_uint8*src_u8=(const ma_uint8*)src;
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=src_u8[i];
x=x-128;
x=x<<24;
dst_s32[i]=x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_u8_to_s32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_u8_to_s32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_u8_to_s32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_u8_to_s32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_u8_to_s32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_u8_to_s32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_u8_to_s32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_u8_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_u8_to_f32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
float*dst_f32=(float*)dst;
const ma_uint8*src_u8=(const ma_uint8*)src;
M6 i;
for (i=0; i<count; i+=1) {
float x=(float)src_u8[i];
x=x*0.00784313725490196078f;
x=x-1;
dst_f32[i]=x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_u8_to_f32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_f32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_u8_to_f32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_u8_to_f32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_u8_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_u8_to_f32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_u8_to_f32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_u8_to_f32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_u8_to_f32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_u8_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
}
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
static MA_INLINE Mv ma_pcm_interleave_u8__reference(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_uint8*dst_u8=(ma_uint8*)dst;
const ma_uint8**src_u8=(const ma_uint8**)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_u8[iFrame*Mh+iChannel]=src_u8[iChannel][iFrame];
}
}
}
#else
static MA_INLINE Mv ma_pcm_interleave_u8__optimized(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_uint8*dst_u8=(ma_uint8*)dst;
const ma_uint8**src_u8=(const ma_uint8**)src;
if (Mh==1) {
ma_copy_memory_64(dst,src[0],frameCount*sizeof(ma_uint8));
} else if (Mh==2) {
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
dst_u8[iFrame*2+0]=src_u8[0][iFrame];
dst_u8[iFrame*2+1]=src_u8[1][iFrame];
}
} else {
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_u8[iFrame*Mh+iChannel]=src_u8[iChannel][iFrame];
}
}
}
}
#endif
MA_API Mv ma_pcm_interleave_u8(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_interleave_u8__reference(dst,src,frameCount,Mh);
#else
ma_pcm_interleave_u8__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_deinterleave_u8__reference(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_uint8**dst_u8=(ma_uint8**)dst;
const ma_uint8*src_u8=(const ma_uint8*)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_u8[iChannel][iFrame]=src_u8[iFrame*Mh+iChannel];
}
}
}
static MA_INLINE Mv ma_pcm_deinterleave_u8__optimized(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_pcm_deinterleave_u8__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_deinterleave_u8(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_deinterleave_u8__reference(dst,src,frameCount,Mh);
#else
ma_pcm_deinterleave_u8__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_s16_to_u8__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_u8=(ma_uint8*)dst;
const ma_int16*src_s16=(const ma_int16*)src;
if (ditherMode==ma_dither_mode_none) {
M6 i;
for (i=0; i<count; i+=1) {
ma_int16 x=src_s16[i];
x=(ma_int16)(x>>8);
x=(ma_int16)(x+128);
dst_u8[i]=(ma_uint8)x;
}
} else {
M6 i;
for (i=0; i<count; i+=1) {
ma_int16 x=src_s16[i];
ma_int32 dither=ma_dither_s32(ditherMode,-0x80,0x7F);
if ((x+dither)<=0x7FFF) {
x=(ma_int16)(x+dither);
} else {
x=0x7FFF;
}
x=(ma_int16)(x>>8);
x=(ma_int16)(x+128);
dst_u8[i]=(ma_uint8)x;
}
}
}
static MA_INLINE Mv ma_pcm_s16_to_u8__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_u8__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s16_to_u8__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s16_to_u8__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s16_to_u8(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s16_to_u8__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s16_to_u8__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s16_to_u8__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s16_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
}
MA_API Mv ma_pcm_s16_to_s16(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
(Mv)ditherMode;
ma_copy_memory_64(dst,src,count*sizeof(ma_int16));
}
static MA_INLINE Mv ma_pcm_s16_to_s24__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_s24=(ma_uint8*)dst;
const ma_int16*src_s16=(const ma_int16*)src;
M6 i;
for (i=0; i<count; i+=1) {
dst_s24[i*3+0]=0;
dst_s24[i*3+1]=(ma_uint8)(src_s16[i]&0xFF);
dst_s24[i*3+2]=(ma_uint8)(src_s16[i]>>8);
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s16_to_s24__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_s24__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s16_to_s24__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s16_to_s24__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s16_to_s24(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s16_to_s24__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s16_to_s24__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s16_to_s24__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s16_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_s16_to_s32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int32*dst_s32=(ma_int32*)dst;
const ma_int16*src_s16=(const ma_int16*)src;
M6 i;
for (i=0; i<count; i+=1) {
dst_s32[i]=src_s16[i]<<16;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s16_to_s32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_s32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s16_to_s32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s16_to_s32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s16_to_s32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s16_to_s32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s16_to_s32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s16_to_s32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s16_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_s16_to_f32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
float*dst_f32=(float*)dst;
const ma_int16*src_s16=(const ma_int16*)src;
M6 i;
for (i=0; i<count; i+=1) {
float x=(float)src_s16[i];
#if 0
x=x+32768.0f;
x=x*0.00003051804379339284f;
x=x-1;
#else
x=x*0.000030517578125f;
#endif
dst_f32[i]=x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s16_to_f32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_f32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s16_to_f32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s16_to_f32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s16_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s16_to_f32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s16_to_f32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s16_to_f32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s16_to_f32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s16_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_interleave_s16__reference(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_int16*dst_s16=(ma_int16*)dst;
const ma_int16**src_s16=(const ma_int16**)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_s16[iFrame*Mh+iChannel]=src_s16[iChannel][iFrame];
}
}
}
static MA_INLINE Mv ma_pcm_interleave_s16__optimized(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_pcm_interleave_s16__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_interleave_s16(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_interleave_s16__reference(dst,src,frameCount,Mh);
#else
ma_pcm_interleave_s16__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_deinterleave_s16__reference(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_int16**dst_s16=(ma_int16**)dst;
const ma_int16*src_s16=(const ma_int16*)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_s16[iChannel][iFrame]=src_s16[iFrame*Mh+iChannel];
}
}
}
static MA_INLINE Mv ma_pcm_deinterleave_s16__optimized(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_pcm_deinterleave_s16__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_deinterleave_s16(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_deinterleave_s16__reference(dst,src,frameCount,Mh);
#else
ma_pcm_deinterleave_s16__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_s24_to_u8__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_u8=(ma_uint8*)dst;
const ma_uint8*src_s24=(const ma_uint8*)src;
if (ditherMode==ma_dither_mode_none) {
M6 i;
for (i=0; i<count; i+=1) {
dst_u8[i]=(ma_uint8)((ma_int8)src_s24[i*3+2]+128);
}
} else {
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=(ma_int32)(((M3)(src_s24[i*3+0])<<8)|((M3)(src_s24[i*3+1])<<16)|((M3)(src_s24[i*3+2]))<<24);
ma_int32 dither=ma_dither_s32(ditherMode,-0x800000,0x7FFFFF);
if ((ma_int64)x+dither<=0x7FFFFFFF) {
x=x+dither;
} else {
x=0x7FFFFFFF;
}
x=x>>24;
x=x+128;
dst_u8[i]=(ma_uint8)x;
}
}
}
static MA_INLINE Mv ma_pcm_s24_to_u8__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_u8__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s24_to_u8__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s24_to_u8__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s24_to_u8(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s24_to_u8__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s24_to_u8__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s24_to_u8__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s24_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_s24_to_s16__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int16*dst_s16=(ma_int16*)dst;
const ma_uint8*src_s24=(const ma_uint8*)src;
if (ditherMode==ma_dither_mode_none) {
M6 i;
for (i=0; i<count; i+=1) {
ma_uint16 dst_lo=((ma_uint16)src_s24[i*3+1]);
ma_uint16 dst_hi=(ma_uint16)((ma_uint16)src_s24[i*3+2]<<8);
dst_s16[i]=(ma_int16)(dst_lo|dst_hi);
}
} else {
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=(ma_int32)(((M3)(src_s24[i*3+0])<<8)|((M3)(src_s24[i*3+1])<<16)|((M3)(src_s24[i*3+2]))<<24);
ma_int32 dither=ma_dither_s32(ditherMode,-0x8000,0x7FFF);
if ((ma_int64)x+dither<=0x7FFFFFFF) {
x=x+dither;
} else {
x=0x7FFFFFFF;
}
x=x>>16;
dst_s16[i]=(ma_int16)x;
}
}
}
static MA_INLINE Mv ma_pcm_s24_to_s16__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_s16__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s24_to_s16__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s24_to_s16__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s24_to_s16(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s24_to_s16__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s24_to_s16__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s24_to_s16__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s24_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
}
MA_API Mv ma_pcm_s24_to_s24(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
(Mv)ditherMode;
ma_copy_memory_64(dst,src,count*3);
}
static MA_INLINE Mv ma_pcm_s24_to_s32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int32*dst_s32=(ma_int32*)dst;
const ma_uint8*src_s24=(const ma_uint8*)src;
M6 i;
for (i=0; i<count; i+=1) {
dst_s32[i]=(ma_int32)(((M3)(src_s24[i*3+0])<<8)|((M3)(src_s24[i*3+1])<<16)|((M3)(src_s24[i*3+2]))<<24);
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s24_to_s32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_s32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s24_to_s32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s24_to_s32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s24_to_s32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s24_to_s32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s24_to_s32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s24_to_s32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s24_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_s24_to_f32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
float*dst_f32=(float*)dst;
const ma_uint8*src_s24=(const ma_uint8*)src;
M6 i;
for (i=0; i<count; i+=1) {
float x=(float)(((ma_int32)(((M3)(src_s24[i*3+0])<<8)|((M3)(src_s24[i*3+1])<<16)|((M3)(src_s24[i*3+2]))<<24))>>8);
#if 0
x=x+8388608.0f;
x=x*0.00000011920929665621f;
x=x-1;
#else
x=x*0.00000011920928955078125f;
#endif
dst_f32[i]=x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s24_to_f32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_f32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s24_to_f32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s24_to_f32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s24_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s24_to_f32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s24_to_f32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s24_to_f32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s24_to_f32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s24_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_interleave_s24__reference(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_uint8*dst8=(ma_uint8*)dst;
const ma_uint8**src8=(const ma_uint8**)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst8[iFrame*3*Mh+iChannel*3+0]=src8[iChannel][iFrame*3+0];
dst8[iFrame*3*Mh+iChannel*3+1]=src8[iChannel][iFrame*3+1];
dst8[iFrame*3*Mh+iChannel*3+2]=src8[iChannel][iFrame*3+2];
}
}
}
static MA_INLINE Mv ma_pcm_interleave_s24__optimized(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_pcm_interleave_s24__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_interleave_s24(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_interleave_s24__reference(dst,src,frameCount,Mh);
#else
ma_pcm_interleave_s24__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_deinterleave_s24__reference(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_uint8**dst8=(ma_uint8**)dst;
const ma_uint8*src8=(const ma_uint8*)src;
M3 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst8[iChannel][iFrame*3+0]=src8[iFrame*3*Mh+iChannel*3+0];
dst8[iChannel][iFrame*3+1]=src8[iFrame*3*Mh+iChannel*3+1];
dst8[iChannel][iFrame*3+2]=src8[iFrame*3*Mh+iChannel*3+2];
}
}
}
static MA_INLINE Mv ma_pcm_deinterleave_s24__optimized(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_pcm_deinterleave_s24__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_deinterleave_s24(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_deinterleave_s24__reference(dst,src,frameCount,Mh);
#else
ma_pcm_deinterleave_s24__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_s32_to_u8__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_u8=(ma_uint8*)dst;
const ma_int32*src_s32=(const ma_int32*)src;
if (ditherMode==ma_dither_mode_none) {
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=src_s32[i];
x=x>>24;
x=x+128;
dst_u8[i]=(ma_uint8)x;
}
} else {
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=src_s32[i];
ma_int32 dither=ma_dither_s32(ditherMode,-0x800000,0x7FFFFF);
if ((ma_int64)x+dither<=0x7FFFFFFF) {
x=x+dither;
} else {
x=0x7FFFFFFF;
}
x=x>>24;
x=x+128;
dst_u8[i]=(ma_uint8)x;
}
}
}
static MA_INLINE Mv ma_pcm_s32_to_u8__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_u8__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s32_to_u8__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s32_to_u8__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s32_to_u8(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s32_to_u8__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s32_to_u8__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s32_to_u8__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s32_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_s32_to_s16__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int16*dst_s16=(ma_int16*)dst;
const ma_int32*src_s32=(const ma_int32*)src;
if (ditherMode==ma_dither_mode_none) {
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=src_s32[i];
x=x>>16;
dst_s16[i]=(ma_int16)x;
}
} else {
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 x=src_s32[i];
ma_int32 dither=ma_dither_s32(ditherMode,-0x8000,0x7FFF);
if ((ma_int64)x+dither<=0x7FFFFFFF) {
x=x+dither;
} else {
x=0x7FFFFFFF;
}
x=x>>16;
dst_s16[i]=(ma_int16)x;
}
}
}
static MA_INLINE Mv ma_pcm_s32_to_s16__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_s16__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s32_to_s16__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s32_to_s16__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s32_to_s16(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s32_to_s16__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s32_to_s16__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s32_to_s16__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s32_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_s32_to_s24__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_s24=(ma_uint8*)dst;
const ma_int32*src_s32=(const ma_int32*)src;
M6 i;
for (i=0; i<count; i+=1) {
M3 x=(M3)src_s32[i];
dst_s24[i*3+0]=(ma_uint8)((x&0x0000FF00)>>8);
dst_s24[i*3+1]=(ma_uint8)((x&0x00FF0000)>>16);
dst_s24[i*3+2]=(ma_uint8)((x&0xFF000000)>>24);
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s32_to_s24__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_s24__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s32_to_s24__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s32_to_s24__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s32_to_s24(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s32_to_s24__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s32_to_s24__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s32_to_s24__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s32_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
}
MA_API Mv ma_pcm_s32_to_s32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
(Mv)ditherMode;
ma_copy_memory_64(dst,src,count*sizeof(ma_int32));
}
static MA_INLINE Mv ma_pcm_s32_to_f32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
float*dst_f32=(float*)dst;
const ma_int32*src_s32=(const ma_int32*)src;
M6 i;
for (i=0; i<count; i+=1) {
double x=src_s32[i];
#if 0
x=x+2147483648.0;
x=x*0.0000000004656612873077392578125;
x=x-1;
#else
x=x / 2147483648.0;
#endif
dst_f32[i]=(float)x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_s32_to_f32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_f32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_s32_to_f32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_s32_to_f32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_s32_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_s32_to_f32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_s32_to_f32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_s32_to_f32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_s32_to_f32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_s32_to_f32__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_interleave_s32__reference(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_int32*dst_s32=(ma_int32*)dst;
const ma_int32**src_s32=(const ma_int32**)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_s32[iFrame*Mh+iChannel]=src_s32[iChannel][iFrame];
}
}
}
static MA_INLINE Mv ma_pcm_interleave_s32__optimized(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_pcm_interleave_s32__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_interleave_s32(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_interleave_s32__reference(dst,src,frameCount,Mh);
#else
ma_pcm_interleave_s32__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_deinterleave_s32__reference(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_int32**dst_s32=(ma_int32**)dst;
const ma_int32*src_s32=(const ma_int32*)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_s32[iChannel][iFrame]=src_s32[iFrame*Mh+iChannel];
}
}
}
static MA_INLINE Mv ma_pcm_deinterleave_s32__optimized(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_pcm_deinterleave_s32__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_deinterleave_s32(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_deinterleave_s32__reference(dst,src,frameCount,Mh);
#else
ma_pcm_deinterleave_s32__optimized(dst,src,frameCount,Mh);
#endif
}
static MA_INLINE Mv ma_pcm_f32_to_u8__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
M6 i;
ma_uint8*dst_u8=(ma_uint8*)dst;
const float*src_f32=(const float*)src;
float ditherMin=0;
float ditherMax=0;
if (ditherMode !=ma_dither_mode_none) {
ditherMin=1.0f /-128;
ditherMax=1.0f / 127;
}
for (i=0; i<count; i+=1) {
float x=src_f32[i];
x=x+ma_dither_f32(ditherMode,ditherMin,ditherMax);
x=((x<-1)?-1:((x>1)?1:x));
x=x+1;
x=x*127.5f;
dst_u8[i]=(ma_uint8)x;
}
}
static MA_INLINE Mv ma_pcm_f32_to_u8__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_u8__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_f32_to_u8__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_f32_to_u8__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_f32_to_u8(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_f32_to_u8__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_f32_to_u8__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_f32_to_u8__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_f32_to_u8__optimized(dst,src,count,ditherMode);
}
#endif
}
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
static MA_INLINE Mv ma_pcm_f32_to_s16__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
M6 i;
ma_int16*dst_s16=(ma_int16*)dst;
const float*src_f32=(const float*)src;
float ditherMin=0;
float ditherMax=0;
if (ditherMode !=ma_dither_mode_none) {
ditherMin=1.0f /-32768;
ditherMax=1.0f / 32767;
}
for (i=0; i<count; i+=1) {
float x=src_f32[i];
x=x+ma_dither_f32(ditherMode,ditherMin,ditherMax);
x=((x<-1)?-1:((x>1)?1:x));
#if 0
x=x+1;
x=x*32767.5f;
x=x-32768.0f;
#else
x=x*32767.0f;
#endif
dst_s16[i]=(ma_int16)x;
}
}
#else
static MA_INLINE Mv ma_pcm_f32_to_s16__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
M6 i;
M6 i4;
M6 count4;
ma_int16*dst_s16=(ma_int16*)dst;
const float*src_f32=(const float*)src;
float ditherMin=0;
float ditherMax=0;
if (ditherMode !=ma_dither_mode_none) {
ditherMin=1.0f /-32768;
ditherMax=1.0f / 32767;
}
i=0;
count4=count>>2;
for (i4=0; i4<count4; i4+=1) {
float d0=ma_dither_f32(ditherMode,ditherMin,ditherMax);
float d1=ma_dither_f32(ditherMode,ditherMin,ditherMax);
float d2=ma_dither_f32(ditherMode,ditherMin,ditherMax);
float d3=ma_dither_f32(ditherMode,ditherMin,ditherMax);
float x0=src_f32[i+0];
float x1=src_f32[i+1];
float x2=src_f32[i+2];
float x3=src_f32[i+3];
x0=x0+d0;
x1=x1+d1;
x2=x2+d2;
x3=x3+d3;
x0=((x0<-1)?-1:((x0>1)?1:x0));
x1=((x1<-1)?-1:((x1>1)?1:x1));
x2=((x2<-1)?-1:((x2>1)?1:x2));
x3=((x3<-1)?-1:((x3>1)?1:x3));
x0=x0*32767.0f;
x1=x1*32767.0f;
x2=x2*32767.0f;
x3=x3*32767.0f;
dst_s16[i+0]=(ma_int16)x0;
dst_s16[i+1]=(ma_int16)x1;
dst_s16[i+2]=(ma_int16)x2;
dst_s16[i+3]=(ma_int16)x3;
i+=4;
}
for (; i<count; i+=1) {
float x=src_f32[i];
x=x+ma_dither_f32(ditherMode,ditherMin,ditherMax);
x=((x<-1)?-1:((x>1)?1:x));
x=x*32767.0f;
dst_s16[i]=(ma_int16)x;
}
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_f32_to_s16__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
M6 i;
M6 i8;
M6 count8;
ma_int16*dst_s16;
const float*src_f32;
float ditherMin;
float ditherMax;
if ((((ma_uintptr)dst&15) !=0)||(((ma_uintptr)src&15) !=0)) {
ma_pcm_f32_to_s16__optimized(dst,src,count,ditherMode);
Mr;
}
dst_s16=(ma_int16*)dst;
src_f32=(const float*)src;
ditherMin=0;
ditherMax=0;
if (ditherMode !=ma_dither_mode_none) {
ditherMin=1.0f /-32768;
ditherMax=1.0f / 32767;
}
i=0;
count8=count>>3;
for (i8=0; i8<count8; i8+=1) {
__m128 d0;
__m128 d1;
__m128 x0;
__m128 x1;
if (ditherMode==ma_dither_mode_none) {
d0=_mm_set1_ps(0);
d1=_mm_set1_ps(0);
} else if (ditherMode==ma_dither_mode_rectangle) {
d0=_mm_set_ps(
ma_dither_f32_rectangle(ditherMin,ditherMax),ma_dither_f32_rectangle(ditherMin,ditherMax),ma_dither_f32_rectangle(ditherMin,ditherMax),ma_dither_f32_rectangle(ditherMin,ditherMax)
);
d1=_mm_set_ps(
ma_dither_f32_rectangle(ditherMin,ditherMax),ma_dither_f32_rectangle(ditherMin,ditherMax),ma_dither_f32_rectangle(ditherMin,ditherMax),ma_dither_f32_rectangle(ditherMin,ditherMax)
);
} else {
d0=_mm_set_ps(
ma_dither_f32_triangle(ditherMin,ditherMax),ma_dither_f32_triangle(ditherMin,ditherMax),ma_dither_f32_triangle(ditherMin,ditherMax),ma_dither_f32_triangle(ditherMin,ditherMax)
);
d1=_mm_set_ps(
ma_dither_f32_triangle(ditherMin,ditherMax),ma_dither_f32_triangle(ditherMin,ditherMax),ma_dither_f32_triangle(ditherMin,ditherMax),ma_dither_f32_triangle(ditherMin,ditherMax)
);
}
x0=*((__m128*)(src_f32+i)+0);
x1=*((__m128*)(src_f32+i)+1);
x0=_mm_add_ps(x0,d0);
x1=_mm_add_ps(x1,d1);
x0=_mm_mul_ps(x0,_mm_set1_ps(32767.0f));
x1=_mm_mul_ps(x1,_mm_set1_ps(32767.0f));
_mm_stream_si128(((__m128i*)(dst_s16+i)),_mm_packs_epi32(_mm_cvttps_epi32(x0),_mm_cvttps_epi32(x1)));
i+=8;
}
for (; i<count; i+=1) {
float x=src_f32[i];
x=x+ma_dither_f32(ditherMode,ditherMin,ditherMax);
x=((x<-1)?-1:((x>1)?1:x));
x=x*32767.0f;
dst_s16[i]=(ma_int16)x;
}
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_f32_to_s16__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
M6 i;
M6 i8;
M6 count8;
ma_int16*dst_s16;
const float*src_f32;
float ditherMin;
float ditherMax;
if (!ma_has_neon()) {
ma_pcm_f32_to_s16__optimized(dst,src,count,ditherMode);
Mr;
}
if ((((ma_uintptr)dst&15) !=0)||(((ma_uintptr)src&15) !=0)) {
ma_pcm_f32_to_s16__optimized(dst,src,count,ditherMode);
Mr;
}
dst_s16=(ma_int16*)dst;
src_f32=(const float*)src;
ditherMin=0;
ditherMax=0;
if (ditherMode !=ma_dither_mode_none) {
ditherMin=1.0f /-32768;
ditherMax=1.0f / 32767;
}
i=0;
count8=count>>3;
for (i8=0; i8<count8; i8+=1) {
float32x4_t d0;
float32x4_t d1;
float32x4_t x0;
float32x4_t x1;
int32x4_t i0;
int32x4_t i1;
if (ditherMode==ma_dither_mode_none) {
d0=vmovq_n_f32(0);
d1=vmovq_n_f32(0);
} else if (ditherMode==ma_dither_mode_rectangle) {
float d0v[4];
float d1v[4];
d0v[0]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d0v[1]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d0v[2]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d0v[3]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d0=vld1q_f32(d0v);
d1v[0]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d1v[1]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d1v[2]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d1v[3]=ma_dither_f32_rectangle(ditherMin,ditherMax);
d1=vld1q_f32(d1v);
} else {
float d0v[4];
float d1v[4];
d0v[0]=ma_dither_f32_triangle(ditherMin,ditherMax);
d0v[1]=ma_dither_f32_triangle(ditherMin,ditherMax);
d0v[2]=ma_dither_f32_triangle(ditherMin,ditherMax);
d0v[3]=ma_dither_f32_triangle(ditherMin,ditherMax);
d0=vld1q_f32(d0v);
d1v[0]=ma_dither_f32_triangle(ditherMin,ditherMax);
d1v[1]=ma_dither_f32_triangle(ditherMin,ditherMax);
d1v[2]=ma_dither_f32_triangle(ditherMin,ditherMax);
d1v[3]=ma_dither_f32_triangle(ditherMin,ditherMax);
d1=vld1q_f32(d1v);
}
x0=*((float32x4_t*)(src_f32+i)+0);
x1=*((float32x4_t*)(src_f32+i)+1);
x0=vaddq_f32(x0,d0);
x1=vaddq_f32(x1,d1);
x0=vmulq_n_f32(x0,32767.0f);
x1=vmulq_n_f32(x1,32767.0f);
i0=vcvtq_s32_f32(x0);
i1=vcvtq_s32_f32(x1);
*((int16x8_t*)(dst_s16+i))=vcombine_s16(vqmovn_s32(i0),vqmovn_s32(i1));
i+=8;
}
for (; i<count; i+=1) {
float x=src_f32[i];
x=x+ma_dither_f32(ditherMode,ditherMin,ditherMax);
x=((x<-1)?-1:((x>1)?1:x));
x=x*32767.0f;
dst_s16[i]=(ma_int16)x;
}
}
#endif
#endif
MA_API Mv ma_pcm_f32_to_s16(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_f32_to_s16__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_f32_to_s16__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_f32_to_s16__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_f32_to_s16__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_f32_to_s24__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_uint8*dst_s24=(ma_uint8*)dst;
const float*src_f32=(const float*)src;
M6 i;
for (i=0; i<count; i+=1) {
ma_int32 r;
float x=src_f32[i];
x=((x<-1)?-1:((x>1)?1:x));
#if 0
x=x+1;
x=x*8388607.5f;
x=x-8388608.0f;
#else
x=x*8388607.0f;
#endif
r=(ma_int32)x;
dst_s24[(i*3)+0]=(ma_uint8)((r&0x0000FF)>>0);
dst_s24[(i*3)+1]=(ma_uint8)((r&0x00FF00)>>8);
dst_s24[(i*3)+2]=(ma_uint8)((r&0xFF0000)>>16);
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_f32_to_s24__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_s24__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_f32_to_s24__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_f32_to_s24__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_f32_to_s24(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_f32_to_s24__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_f32_to_s24__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_f32_to_s24__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_f32_to_s24__optimized(dst,src,count,ditherMode);
}
#endif
}
static MA_INLINE Mv ma_pcm_f32_to_s32__reference(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_int32*dst_s32=(ma_int32*)dst;
const float*src_f32=(const float*)src;
M3 i;
for (i=0; i<count; i+=1) {
double x=src_f32[i];
x=((x<-1)?-1:((x>1)?1:x));
#if 0
x=x+1;
x=x*2147483647.5;
x=x-2147483648.0;
#else
x=x*2147483647.0;
#endif
dst_s32[i]=(ma_int32)x;
}
(Mv)ditherMode;
}
static MA_INLINE Mv ma_pcm_f32_to_s32__optimized(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_s32__reference(dst,src,count,ditherMode);
}
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE Mv ma_pcm_f32_to_s32__sse2(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE Mv ma_pcm_f32_to_s32__neon(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
ma_pcm_f32_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
MA_API Mv ma_pcm_f32_to_s32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_f32_to_s32__reference(dst,src,count,ditherMode);
#else
# if defined(MA_SUPPORT_SSE2)
if (ma_has_sse2()) {
ma_pcm_f32_to_s32__sse2(dst,src,count,ditherMode);
} else
#elif defined(MA_SUPPORT_NEON)
if (ma_has_neon()) {
ma_pcm_f32_to_s32__neon(dst,src,count,ditherMode);
} else
#endif
{
ma_pcm_f32_to_s32__optimized(dst,src,count,ditherMode);
}
#endif
}
MA_API Mv ma_pcm_f32_to_f32(Mv*dst,const Mv*src,M6 count,ma_dither_mode ditherMode)
{
(Mv)ditherMode;
ma_copy_memory_64(dst,src,count*sizeof(float));
}
static Mv ma_pcm_interleave_f32__reference(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
float*dst_f32=(float*)dst;
const float**src_f32=(const float**)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_f32[iFrame*Mh+iChannel]=src_f32[iChannel][iFrame];
}
}
}
static Mv ma_pcm_interleave_f32__optimized(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
ma_pcm_interleave_f32__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_interleave_f32(Mv*dst,const Mv**src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_interleave_f32__reference(dst,src,frameCount,Mh);
#else
ma_pcm_interleave_f32__optimized(dst,src,frameCount,Mh);
#endif
}
static Mv ma_pcm_deinterleave_f32__reference(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
float**dst_f32=(float**)dst;
const float*src_f32=(const float*)src;
M6 iFrame;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
dst_f32[iChannel][iFrame]=src_f32[iFrame*Mh+iChannel];
}
}
}
static Mv ma_pcm_deinterleave_f32__optimized(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
ma_pcm_deinterleave_f32__reference(dst,src,frameCount,Mh);
}
MA_API Mv ma_pcm_deinterleave_f32(Mv**dst,const Mv*src,M6 frameCount,M3 Mh)
{
#ifdef MA_USE_REFERENCE_CONVERSION_APIS
ma_pcm_deinterleave_f32__reference(dst,src,frameCount,Mh);
#else
ma_pcm_deinterleave_f32__optimized(dst,src,frameCount,Mh);
#endif
}
MA_API Mv ma_pcm_convert(Mv*pOut,ma_format formatOut,const Mv*pIn,ma_format formatIn,M6 sampleCount,ma_dither_mode ditherMode)
{
if (formatOut==formatIn) {
ma_copy_memory_64(pOut,pIn,sampleCount*ma_get_bytes_per_sample(formatOut));
Mr;
}
switch (formatIn)
{
case ma_format_u8:
{
switch (formatOut)
{
case ma_format_s16:ma_pcm_u8_to_s16(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s24:ma_pcm_u8_to_s24(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s32:ma_pcm_u8_to_s32(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_f32:ma_pcm_u8_to_f32(pOut,pIn,sampleCount,ditherMode); Mr;
default:break;
}
} break;
case ma_format_s16:
{
switch (formatOut)
{
case ma_format_u8:ma_pcm_s16_to_u8( pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s24:ma_pcm_s16_to_s24(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s32:ma_pcm_s16_to_s32(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_f32:ma_pcm_s16_to_f32(pOut,pIn,sampleCount,ditherMode); Mr;
default:break;
}
} break;
case ma_format_s24:
{
switch (formatOut)
{
case ma_format_u8:ma_pcm_s24_to_u8( pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s16:ma_pcm_s24_to_s16(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s32:ma_pcm_s24_to_s32(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_f32:ma_pcm_s24_to_f32(pOut,pIn,sampleCount,ditherMode); Mr;
default:break;
}
} break;
case ma_format_s32:
{
switch (formatOut)
{
case ma_format_u8:ma_pcm_s32_to_u8( pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s16:ma_pcm_s32_to_s16(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s24:ma_pcm_s32_to_s24(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_f32:ma_pcm_s32_to_f32(pOut,pIn,sampleCount,ditherMode); Mr;
default:break;
}
} break;
case ma_format_f32:
{
switch (formatOut)
{
case ma_format_u8:ma_pcm_f32_to_u8( pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s16:ma_pcm_f32_to_s16(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s24:ma_pcm_f32_to_s24(pOut,pIn,sampleCount,ditherMode); Mr;
case ma_format_s32:ma_pcm_f32_to_s32(pOut,pIn,sampleCount,ditherMode); Mr;
default:break;
}
} break;
default:break;
}
}
MA_API Mv ma_convert_pcm_frames_format(Mv*pOut,ma_format formatOut,const Mv*pIn,ma_format formatIn,M6 frameCount,M3 Mh,ma_dither_mode ditherMode)
{
ma_pcm_convert(pOut,formatOut,pIn,formatIn,frameCount*Mh,ditherMode);
}
MA_API Mv ma_deinterleave_pcm_frames(ma_format format,M3 Mh,M6 frameCount,const Mv*pInterleavedPCMFrames,Mv**ppDeinterleavedPCMFrames)
{
if (pInterleavedPCMFrames==NULL||ppDeinterleavedPCMFrames==NULL) {
Mr;
}
switch (format) {
case ma_format_s16:
{
const ma_int16*pSrcS16=(const ma_int16*)pInterleavedPCMFrames;
M6 iPCMFrame;
for (iPCMFrame=0; iPCMFrame<frameCount;++iPCMFrame) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
 ma_int16*pDstS16=(ma_int16*)ppDeinterleavedPCMFrames[iChannel];
 pDstS16[iPCMFrame]=pSrcS16[iPCMFrame*Mh+iChannel];
}
}
} break;
case ma_format_f32:
{
const float*pSrcF32=(const float*)pInterleavedPCMFrames;
M6 iPCMFrame;
for (iPCMFrame=0; iPCMFrame<frameCount;++iPCMFrame) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
 float*pDstF32=(float*)ppDeinterleavedPCMFrames[iChannel];
 pDstF32[iPCMFrame]=pSrcF32[iPCMFrame*Mh+iChannel];
}
}
} break;
default:
{
M3 sampleSizeInBytes=ma_get_bytes_per_sample(format);
M6 iPCMFrame;
for (iPCMFrame=0; iPCMFrame<frameCount;++iPCMFrame) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
 Mv*pDst=ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel],iPCMFrame*sampleSizeInBytes);
 const Mv*pSrc=ma_offset_ptr(pInterleavedPCMFrames,(iPCMFrame*Mh+iChannel)*sampleSizeInBytes);
 memcpy(pDst,pSrc,sampleSizeInBytes);
}
}
} break;
}
}
MA_API Mv ma_interleave_pcm_frames(ma_format format,M3 Mh,M6 frameCount,const Mv**ppDeinterleavedPCMFrames,Mv*pInterleavedPCMFrames)
{
switch (format)
{
case ma_format_s16:
{
ma_int16*pDstS16=(ma_int16*)pInterleavedPCMFrames;
M6 iPCMFrame;
for (iPCMFrame=0; iPCMFrame<frameCount;++iPCMFrame) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
 const ma_int16*pSrcS16=(const ma_int16*)ppDeinterleavedPCMFrames[iChannel];
 pDstS16[iPCMFrame*Mh+iChannel]=pSrcS16[iPCMFrame];
}
}
} break;
case ma_format_f32:
{
float*pDstF32=(float*)pInterleavedPCMFrames;
M6 iPCMFrame;
for (iPCMFrame=0; iPCMFrame<frameCount;++iPCMFrame) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
 const float*pSrcF32=(const float*)ppDeinterleavedPCMFrames[iChannel];
 pDstF32[iPCMFrame*Mh+iChannel]=pSrcF32[iPCMFrame];
}
}
} break;
default:
{
M3 sampleSizeInBytes=ma_get_bytes_per_sample(format);
M6 iPCMFrame;
for (iPCMFrame=0; iPCMFrame<frameCount;++iPCMFrame) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
 Mv*pDst=ma_offset_ptr(pInterleavedPCMFrames,(iPCMFrame*Mh+iChannel)*sampleSizeInBytes);
 const Mv*pSrc=ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel],iPCMFrame*sampleSizeInBytes);
 memcpy(pDst,pSrc,sampleSizeInBytes);
}
}
} break;
}
}
#ifndef MA_BIQUAD_FIXED_POINT_SHIFT
#define MA_BIQUAD_FIXED_POINT_SHIFT 14
#endif
static ma_int32 ma_biquad_float_to_fp(double x)
{
Mr (ma_int32)(x*(1<<MA_BIQUAD_FIXED_POINT_SHIFT));
}
MA_API ma_biquad_config ma_biquad_config_init(ma_format format,M3 Mh,double b0,double b1,double b2,double a0,double a1,double a2)
{
ma_biquad_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.b0=b0;
config.b1=b1;
config.b2=b2;
config.a0=a0;
config.a1=a1;
config.a2=a2;
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t r1Offset;
size_t r2Offset;
} ma_biquad_heap_layout;
static Me ma_biquad_get_heap_layout(const ma_biquad_config*Mo,ma_biquad_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->r1Offset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=sizeof(ma_biquad_coefficient)*Mo->Mh;
pHeapLayout->r2Offset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=sizeof(ma_biquad_coefficient)*Mo->Mh;
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_biquad_get_heap_size(const ma_biquad_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_biquad_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_biquad_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_biquad_init_preallocated(const ma_biquad_config*Mo,Mv*pHeap,ma_biquad*pBQ)
{
Me Mf;
ma_biquad_heap_layout heapLayout;
if (pBQ==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pBQ);
Mf=ma_biquad_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pBQ->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pBQ->pR1=(ma_biquad_coefficient*)ma_offset_ptr(pHeap,heapLayout.r1Offset);
pBQ->pR2=(ma_biquad_coefficient*)ma_offset_ptr(pHeap,heapLayout.r2Offset);
Mr ma_biquad_reinit(Mo,pBQ);
}
MA_API Me ma_biquad_init(const ma_biquad_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_biquad*pBQ)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_biquad_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_biquad_init_preallocated(Mo,pHeap,pBQ);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pBQ->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_biquad_uninit(ma_biquad*pBQ,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pBQ==NULL) {
Mr;
}
if (pBQ->_ownsHeap) {
ma_free(pBQ->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_biquad_reinit(const ma_biquad_config*Mo,ma_biquad*pBQ)
{
if (pBQ==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->a0==0) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (pBQ->format !=ma_format_unknown&&pBQ->format !=Mo->format) {
Mr MA_INVALID_OPERATION;
}
if (pBQ->Mh !=0&&pBQ->Mh !=Mo->Mh) {
Mr MA_INVALID_OPERATION;
}
pBQ->format=Mo->format;
pBQ->Mh=Mo->Mh;
if (Mo->format==ma_format_f32) {
pBQ->b0.f32=(float)(Mo->b0 / Mo->a0);
pBQ->b1.f32=(float)(Mo->b1 / Mo->a0);
pBQ->b2.f32=(float)(Mo->b2 / Mo->a0);
pBQ->a1.f32=(float)(Mo->a1 / Mo->a0);
pBQ->a2.f32=(float)(Mo->a2 / Mo->a0);
} else {
pBQ->b0.s32=ma_biquad_float_to_fp(Mo->b0 / Mo->a0);
pBQ->b1.s32=ma_biquad_float_to_fp(Mo->b1 / Mo->a0);
pBQ->b2.s32=ma_biquad_float_to_fp(Mo->b2 / Mo->a0);
pBQ->a1.s32=ma_biquad_float_to_fp(Mo->a1 / Mo->a0);
pBQ->a2.s32=ma_biquad_float_to_fp(Mo->a2 / Mo->a0);
}
Mr Ms;
}
MA_API Me ma_biquad_clear_cache(ma_biquad*pBQ)
{
if (pBQ==NULL) {
Mr MA_INVALID_ARGS;
}
if (pBQ->format==ma_format_f32) {
pBQ->pR1->f32=0;
pBQ->pR2->f32=0;
} else {
pBQ->pR1->s32=0;
pBQ->pR2->s32=0;
}
Mr Ms;
}
static MA_INLINE Mv ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad*pBQ,float*pY,const float*pX)
{
M3 c;
const M3 Mh=pBQ->Mh;
const float b0=pBQ->b0.f32;
const float b1=pBQ->b1.f32;
const float b2=pBQ->b2.f32;
const float a1=pBQ->a1.f32;
const float a2=pBQ->a2.f32;
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
float r1=pBQ->pR1[c].f32;
float r2=pBQ->pR2[c].f32;
float x=pX[c];
float y;
y=b0*x+r1;
r1=b1*x-a1*y+r2;
r2=b2*x-a2*y;
pY[c]=y;
pBQ->pR1[c].f32=r1;
pBQ->pR2[c].f32=r2;
}
}
static MA_INLINE Mv ma_biquad_process_pcm_frame_f32(ma_biquad*pBQ,float*pY,const float*pX)
{
ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ,pY,pX);
}
static MA_INLINE Mv ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad*pBQ,ma_int16*pY,const ma_int16*pX)
{
M3 c;
const M3 Mh=pBQ->Mh;
const ma_int32 b0=pBQ->b0.s32;
const ma_int32 b1=pBQ->b1.s32;
const ma_int32 b2=pBQ->b2.s32;
const ma_int32 a1=pBQ->a1.s32;
const ma_int32 a2=pBQ->a2.s32;
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
ma_int32 r1=pBQ->pR1[c].s32;
ma_int32 r2=pBQ->pR2[c].s32;
ma_int32 x=pX[c];
ma_int32 y;
y=(b0*x+r1)>>MA_BIQUAD_FIXED_POINT_SHIFT;
r1=(b1*x-a1*y+r2);
r2=(b2*x-a2*y);
pY[c]=(ma_int16)ma_clamp(y,-32768,32767);
pBQ->pR1[c].s32=r1;
pBQ->pR2[c].s32=r2;
}
}
static MA_INLINE Mv ma_biquad_process_pcm_frame_s16(ma_biquad*pBQ,ma_int16*pY,const ma_int16*pX)
{
ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ,pY,pX);
}
MA_API Me ma_biquad_process_pcm_frames(ma_biquad*pBQ,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
M3 n;
if (pBQ==NULL||pFramesOut==NULL||pFramesIn==NULL) {
Mr MA_INVALID_ARGS;
}
if (pBQ->format==ma_format_f32) { float*pY=( float*)pFramesOut;
const float*pX=(const float*)pFramesIn;
for (n=0; n<frameCount; n+=1) {
ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ,pY,pX);
pY+=pBQ->Mh;
pX+=pBQ->Mh;
}
} else if (pBQ->format==ma_format_s16) { ma_int16*pY=( ma_int16*)pFramesOut;
const ma_int16*pX=(const ma_int16*)pFramesIn;
for (n=0; n<frameCount; n+=1) {
ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ,pY,pX);
pY+=pBQ->Mh;
pX+=pBQ->Mh;
}
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
Mr Ms;
}
MA_API M3 ma_biquad_get_latency(const ma_biquad*pBQ)
{
if (pBQ==NULL) {
Mr 0;
}
Mr 2;
}
MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency)
{
ma_lpf1_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.q=0.5;
Mr config;
}
MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,double q)
{
ma_lpf2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.q=q;
if (config.q==0) {
config.q=0.707107;
}
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t r1Offset;
} ma_lpf1_heap_layout;
static Me ma_lpf1_get_heap_layout(const ma_lpf1_config*Mo,ma_lpf1_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->r1Offset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=sizeof(ma_biquad_coefficient)*Mo->Mh;
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_lpf1_get_heap_size(const ma_lpf1_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_lpf1_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_lpf1_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_lpf1_init_preallocated(const ma_lpf1_config*Mo,Mv*pHeap,ma_lpf1*pLPF)
{
Me Mf;
ma_lpf1_heap_layout heapLayout;
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLPF);
Mf=ma_lpf1_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pLPF->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pLPF->pR1=(ma_biquad_coefficient*)ma_offset_ptr(pHeap,heapLayout.r1Offset);
Mr ma_lpf1_reinit(Mo,pLPF);
}
MA_API Me ma_lpf1_init(const ma_lpf1_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_lpf1*pLPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_lpf1_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_lpf1_init_preallocated(Mo,pHeap,pLPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pLPF->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_lpf1_uninit(ma_lpf1*pLPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pLPF==NULL) {
Mr;
}
if (pLPF->_ownsHeap) {
ma_free(pLPF->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_lpf1_reinit(const ma_lpf1_config*Mo,ma_lpf1*pLPF)
{
double a;
if (pLPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (pLPF->format !=ma_format_unknown&&pLPF->format !=Mo->format) {
Mr MA_INVALID_OPERATION;
}
if (pLPF->Mh !=0&&pLPF->Mh !=Mo->Mh) {
Mr MA_INVALID_OPERATION;
}
pLPF->format=Mo->format;
pLPF->Mh=Mo->Mh;
a=ma_expd(-2*MA_PI_D*Mo->cutoffFrequency / Mo->sampleRate);
if (Mo->format==ma_format_f32) {
pLPF->a.f32=(float)a;
} else {
pLPF->a.s32=ma_biquad_float_to_fp(a);
}
Mr Ms;
}
MA_API Me ma_lpf1_clear_cache(ma_lpf1*pLPF)
{
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
if (pLPF->format==ma_format_f32) {
pLPF->a.f32=0;
} else {
pLPF->a.s32=0;
}
Mr Ms;
}
static MA_INLINE Mv ma_lpf1_process_pcm_frame_f32(ma_lpf1*pLPF,float*pY,const float*pX)
{
M3 c;
const M3 Mh=pLPF->Mh;
const float a=pLPF->a.f32;
const float b=1-a;
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
float r1=pLPF->pR1[c].f32;
float x=pX[c];
float y;
y=b*x+a*r1;
pY[c]=y;
pLPF->pR1[c].f32=y;
}
}
static MA_INLINE Mv ma_lpf1_process_pcm_frame_s16(ma_lpf1*pLPF,ma_int16*pY,const ma_int16*pX)
{
M3 c;
const M3 Mh=pLPF->Mh;
const ma_int32 a=pLPF->a.s32;
const ma_int32 b=((1<<MA_BIQUAD_FIXED_POINT_SHIFT)-a);
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
ma_int32 r1=pLPF->pR1[c].s32;
ma_int32 x=pX[c];
ma_int32 y;
y=(b*x+a*r1)>>MA_BIQUAD_FIXED_POINT_SHIFT;
pY[c]=(ma_int16)y;
pLPF->pR1[c].s32=(ma_int32)y;
}
}
MA_API Me ma_lpf1_process_pcm_frames(ma_lpf1*pLPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
M3 n;
if (pLPF==NULL||pFramesOut==NULL||pFramesIn==NULL) {
Mr MA_INVALID_ARGS;
}
if (pLPF->format==ma_format_f32) { float*pY=( float*)pFramesOut;
const float*pX=(const float*)pFramesIn;
for (n=0; n<frameCount; n+=1) {
ma_lpf1_process_pcm_frame_f32(pLPF,pY,pX);
pY+=pLPF->Mh;
pX+=pLPF->Mh;
}
} else if (pLPF->format==ma_format_s16) { ma_int16*pY=( ma_int16*)pFramesOut;
const ma_int16*pX=(const ma_int16*)pFramesIn;
for (n=0; n<frameCount; n+=1) {
ma_lpf1_process_pcm_frame_s16(pLPF,pY,pX);
pY+=pLPF->Mh;
pX+=pLPF->Mh;
}
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
Mr Ms;
}
MA_API M3 ma_lpf1_get_latency(const ma_lpf1*pLPF)
{
if (pLPF==NULL) {
Mr 0;
}
Mr 1;
}
static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_config*Mo)
{
ma_biquad_config bqConfig;
double q;
double w;
double s;
double c;
double a;
MA_ASSERT(Mo !=NULL);
q=Mo->q;
w=2*MA_PI_D*Mo->cutoffFrequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
a=s / (2*q);
bqConfig.b0=(1-c) / 2;
bqConfig.b1=1-c;
bqConfig.b2=(1-c) / 2;
bqConfig.a0=1+a;
bqConfig.a1=-2*c;
bqConfig.a2=1-a;
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_lpf2_get_heap_size(const ma_lpf2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_lpf2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_lpf2_init_preallocated(const ma_lpf2_config*Mo,Mv*pHeap,ma_lpf2*pLPF)
{
Me Mf;
ma_biquad_config bqConfig;
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLPF);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_lpf2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pLPF->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_lpf2_init(const ma_lpf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_lpf2*pLPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_lpf2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_lpf2_init_preallocated(Mo,pHeap,pLPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pLPF->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_lpf2_uninit(ma_lpf2*pLPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pLPF==NULL) {
Mr;
}
ma_biquad_uninit(&pLPF->bq,pAllocationCallbacks);
}
MA_API Me ma_lpf2_reinit(const ma_lpf2_config*Mo,ma_lpf2*pLPF)
{
Me Mf;
ma_biquad_config bqConfig;
if (pLPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_lpf2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pLPF->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_lpf2_clear_cache(ma_lpf2*pLPF)
{
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
ma_biquad_clear_cache(&pLPF->bq);
Mr Ms;
}
static MA_INLINE Mv ma_lpf2_process_pcm_frame_s16(ma_lpf2*pLPF,ma_int16*pFrameOut,const ma_int16*pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pLPF->bq,pFrameOut,pFrameIn);
}
static MA_INLINE Mv ma_lpf2_process_pcm_frame_f32(ma_lpf2*pLPF,float*pFrameOut,const float*pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pLPF->bq,pFrameOut,pFrameIn);
}
MA_API Me ma_lpf2_process_pcm_frames(ma_lpf2*pLPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pLPF->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_lpf2_get_latency(const ma_lpf2*pLPF)
{
if (pLPF==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pLPF->bq);
}
MA_API ma_lpf_config ma_lpf_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,M3 order)
{
ma_lpf_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.order=ma_min(order,MA_MAX_FILTER_ORDER);
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t lpf1Offset;
size_t lpf2Offset;
} ma_lpf_heap_layout;
static Mv ma_lpf_calculate_sub_lpf_counts(M3 order,M3*pLPF1Count,M3*pLPF2Count)
{
MA_ASSERT(pLPF1Count !=NULL);
MA_ASSERT(pLPF2Count !=NULL);
*pLPF1Count=order % 2;
*pLPF2Count=order / 2;
}
static Me ma_lpf_get_heap_layout(const ma_lpf_config*Mo,ma_lpf_heap_layout*pHeapLayout)
{
Me Mf;
M3 lpf1Count;
M3 lpf2Count;
M3 ilpf1;
M3 ilpf2;
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
if (Mo->order>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
ma_lpf_calculate_sub_lpf_counts(Mo->order,&lpf1Count,&lpf2Count);
pHeapLayout->sizeInBytes=0;
pHeapLayout->lpf1Offset=pHeapLayout->sizeInBytes;
for (ilpf1=0; ilpf1<lpf1Count; ilpf1+=1) {
size_t lpf1HeapSizeInBytes;
ma_lpf1_config lpf1Config=ma_lpf1_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency);
Mf=ma_lpf1_get_heap_size(&lpf1Config,&lpf1HeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=sizeof(ma_lpf1)+lpf1HeapSizeInBytes;
}
pHeapLayout->lpf2Offset=pHeapLayout->sizeInBytes;
for (ilpf2=0; ilpf2<lpf2Count; ilpf2+=1) {
size_t lpf2HeapSizeInBytes;
ma_lpf2_config lpf2Config=ma_lpf2_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency,0.707107);
Mf=ma_lpf2_get_heap_size(&lpf2Config,&lpf2HeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=sizeof(ma_lpf2)+lpf2HeapSizeInBytes;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
static Me ma_lpf_reinit__internal(const ma_lpf_config*Mo,Mv*pHeap,ma_lpf*pLPF,ma_bool32 isNew)
{
Me Mf;
M3 lpf1Count;
M3 lpf2Count;
M3 ilpf1;
M3 ilpf2;
ma_lpf_heap_layout heapLayout;
if (pLPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (pLPF->format !=ma_format_unknown&&pLPF->format !=Mo->format) {
Mr MA_INVALID_OPERATION;
}
if (pLPF->Mh !=0&&pLPF->Mh !=Mo->Mh) {
Mr MA_INVALID_OPERATION;
}
if (Mo->order>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
ma_lpf_calculate_sub_lpf_counts(Mo->order,&lpf1Count,&lpf2Count);
if (!isNew) {
if (pLPF->lpf1Count !=lpf1Count||pLPF->lpf2Count !=lpf2Count) {
Mr MA_INVALID_OPERATION;
}
}
if (isNew) {
Mf=ma_lpf_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pLPF->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pLPF->pLPF1=(ma_lpf1*)ma_offset_ptr(pHeap,heapLayout.lpf1Offset);
pLPF->pLPF2=(ma_lpf2*)ma_offset_ptr(pHeap,heapLayout.lpf2Offset);
} else {
MA_ZERO_OBJECT(&heapLayout);
}
for (ilpf1=0; ilpf1<lpf1Count; ilpf1+=1) {
ma_lpf1_config lpf1Config=ma_lpf1_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency);
if (isNew) {
size_t lpf1HeapSizeInBytes;
Mf=ma_lpf1_get_heap_size(&lpf1Config,&lpf1HeapSizeInBytes);
if (Mf==Ms) {
Mf=ma_lpf1_init_preallocated(&lpf1Config,ma_offset_ptr(pHeap,heapLayout.lpf1Offset+(sizeof(ma_lpf1)*lpf1Count)+(ilpf1*lpf1HeapSizeInBytes)),&pLPF->pLPF1[ilpf1]);
}
} else {
Mf=ma_lpf1_reinit(&lpf1Config,&pLPF->pLPF1[ilpf1]);
}
if (Mf !=Ms) {
M3 jlpf1;
for (jlpf1=0; jlpf1<ilpf1; jlpf1+=1) {
ma_lpf1_uninit(&pLPF->pLPF1[jlpf1],NULL);
}
Mr Mf;
}
}
for (ilpf2=0; ilpf2<lpf2Count; ilpf2+=1) {
ma_lpf2_config lpf2Config;
double q;
double a;
if (lpf1Count==1) {
a=(1+ilpf2*1)*(MA_PI_D/(Mo->order*1));
} else {
a=(1+ilpf2*2)*(MA_PI_D/(Mo->order*2));
}
q=1 / (2*ma_cosd(a));
lpf2Config=ma_lpf2_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency,q);
if (isNew) {
size_t lpf2HeapSizeInBytes;
Mf=ma_lpf2_get_heap_size(&lpf2Config,&lpf2HeapSizeInBytes);
if (Mf==Ms) {
Mf=ma_lpf2_init_preallocated(&lpf2Config,ma_offset_ptr(pHeap,heapLayout.lpf2Offset+(sizeof(ma_lpf2)*lpf2Count)+(ilpf2*lpf2HeapSizeInBytes)),&pLPF->pLPF2[ilpf2]);
}
} else {
Mf=ma_lpf2_reinit(&lpf2Config,&pLPF->pLPF2[ilpf2]);
}
if (Mf !=Ms) {
M3 jlpf1;
M3 jlpf2;
for (jlpf1=0; jlpf1<lpf1Count; jlpf1+=1) {
ma_lpf1_uninit(&pLPF->pLPF1[jlpf1],NULL);
}
for (jlpf2=0; jlpf2<ilpf2; jlpf2+=1) {
ma_lpf2_uninit(&pLPF->pLPF2[jlpf2],NULL);
}
Mr Mf;
}
}
pLPF->lpf1Count=lpf1Count;
pLPF->lpf2Count=lpf2Count;
pLPF->format=Mo->format;
pLPF->Mh=Mo->Mh;
pLPF->sampleRate=Mo->sampleRate;
Mr Ms;
}
MA_API Me ma_lpf_get_heap_size(const ma_lpf_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_lpf_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_lpf_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Mf;
}
MA_API Me ma_lpf_init_preallocated(const ma_lpf_config*Mo,Mv*pHeap,ma_lpf*pLPF)
{
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLPF);
Mr ma_lpf_reinit__internal(Mo,pHeap,pLPF,MA_TRUE);
}
MA_API Me ma_lpf_init(const ma_lpf_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_lpf*pLPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_lpf_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_lpf_init_preallocated(Mo,pHeap,pLPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pLPF->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_lpf_uninit(ma_lpf*pLPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
M3 ilpf1;
M3 ilpf2;
if (pLPF==NULL) {
Mr;
}
for (ilpf1=0; ilpf1<pLPF->lpf1Count; ilpf1+=1) {
ma_lpf1_uninit(&pLPF->pLPF1[ilpf1],pAllocationCallbacks);
}
for (ilpf2=0; ilpf2<pLPF->lpf2Count; ilpf2+=1) {
ma_lpf2_uninit(&pLPF->pLPF2[ilpf2],pAllocationCallbacks);
}
if (pLPF->_ownsHeap) {
ma_free(pLPF->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_lpf_reinit(const ma_lpf_config*Mo,ma_lpf*pLPF)
{
Mr ma_lpf_reinit__internal(Mo,NULL,pLPF,MA_FALSE);
}
MA_API Me ma_lpf_clear_cache(ma_lpf*pLPF)
{
M3 ilpf1;
M3 ilpf2;
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
for (ilpf1=0; ilpf1<pLPF->lpf1Count; ilpf1+=1) {
ma_lpf1_clear_cache(&pLPF->pLPF1[ilpf1]);
}
for (ilpf2=0; ilpf2<pLPF->lpf2Count; ilpf2+=1) {
ma_lpf2_clear_cache(&pLPF->pLPF2[ilpf2]);
}
Mr Ms;
}
static MA_INLINE Mv ma_lpf_process_pcm_frame_f32(ma_lpf*pLPF,float*pY,const Mv*pX)
{
M3 ilpf1;
M3 ilpf2;
MA_ASSERT(pLPF->format==ma_format_f32);
MA_MOVE_MEMORY(pY,pX,ma_get_bytes_per_frame(pLPF->format,pLPF->Mh));
for (ilpf1=0; ilpf1<pLPF->lpf1Count; ilpf1+=1) {
ma_lpf1_process_pcm_frame_f32(&pLPF->pLPF1[ilpf1],pY,pY);
}
for (ilpf2=0; ilpf2<pLPF->lpf2Count; ilpf2+=1) {
ma_lpf2_process_pcm_frame_f32(&pLPF->pLPF2[ilpf2],pY,pY);
}
}
static MA_INLINE Mv ma_lpf_process_pcm_frame_s16(ma_lpf*pLPF,ma_int16*pY,const ma_int16*pX)
{
M3 ilpf1;
M3 ilpf2;
MA_ASSERT(pLPF->format==ma_format_s16);
MA_MOVE_MEMORY(pY,pX,ma_get_bytes_per_frame(pLPF->format,pLPF->Mh));
for (ilpf1=0; ilpf1<pLPF->lpf1Count; ilpf1+=1) {
ma_lpf1_process_pcm_frame_s16(&pLPF->pLPF1[ilpf1],pY,pY);
}
for (ilpf2=0; ilpf2<pLPF->lpf2Count; ilpf2+=1) {
ma_lpf2_process_pcm_frame_s16(&pLPF->pLPF2[ilpf2],pY,pY);
}
}
MA_API Me ma_lpf_process_pcm_frames(ma_lpf*pLPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
Me Mf;
M3 ilpf1;
M3 ilpf2;
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFramesOut==pFramesIn) {
for (ilpf1=0; ilpf1<pLPF->lpf1Count; ilpf1+=1) {
Mf=ma_lpf1_process_pcm_frames(&pLPF->pLPF1[ilpf1],pFramesOut,pFramesOut,frameCount);
if (Mf !=Ms) {
Mr Mf;
}
}
for (ilpf2=0; ilpf2<pLPF->lpf2Count; ilpf2+=1) {
Mf=ma_lpf2_process_pcm_frames(&pLPF->pLPF2[ilpf2],pFramesOut,pFramesOut,frameCount);
if (Mf !=Ms) {
Mr Mf;
}
}
}
if (pFramesOut !=pFramesIn) {
M3 iFrame; if (pLPF->format==ma_format_f32) { float*pFramesOutF32=( float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
ma_lpf_process_pcm_frame_f32(pLPF,pFramesOutF32,pFramesInF32);
pFramesOutF32+=pLPF->Mh;
pFramesInF32+=pLPF->Mh;
}
} else if (pLPF->format==ma_format_s16) { ma_int16*pFramesOutS16=( ma_int16*)pFramesOut;
const ma_int16*pFramesInS16=(const ma_int16*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
ma_lpf_process_pcm_frame_s16(pLPF,pFramesOutS16,pFramesInS16);
pFramesOutS16+=pLPF->Mh;
pFramesInS16+=pLPF->Mh;
}
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_OPERATION;
}
}
Mr Ms;
}
MA_API M3 ma_lpf_get_latency(const ma_lpf*pLPF)
{
if (pLPF==NULL) {
Mr 0;
}
Mr pLPF->lpf2Count*2+pLPF->lpf1Count;
}
MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency)
{
ma_hpf1_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
Mr config;
}
MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,double q)
{
ma_hpf2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.q=q;
if (config.q==0) {
config.q=0.707107;
}
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t r1Offset;
} ma_hpf1_heap_layout;
static Me ma_hpf1_get_heap_layout(const ma_hpf1_config*Mo,ma_hpf1_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->r1Offset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=sizeof(ma_biquad_coefficient)*Mo->Mh;
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_hpf1_get_heap_size(const ma_hpf1_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_hpf1_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_hpf1_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_hpf1_init_preallocated(const ma_hpf1_config*Mo,Mv*pHeap,ma_hpf1*pLPF)
{
Me Mf;
ma_hpf1_heap_layout heapLayout;
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLPF);
Mf=ma_hpf1_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pLPF->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pLPF->pR1=(ma_biquad_coefficient*)ma_offset_ptr(pHeap,heapLayout.r1Offset);
Mr ma_hpf1_reinit(Mo,pLPF);
}
MA_API Me ma_hpf1_init(const ma_hpf1_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hpf1*pLPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_hpf1_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_hpf1_init_preallocated(Mo,pHeap,pLPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pLPF->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_hpf1_uninit(ma_hpf1*pHPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pHPF==NULL) {
Mr;
}
if (pHPF->_ownsHeap) {
ma_free(pHPF->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_hpf1_reinit(const ma_hpf1_config*Mo,ma_hpf1*pHPF)
{
double a;
if (pHPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (pHPF->format !=ma_format_unknown&&pHPF->format !=Mo->format) {
Mr MA_INVALID_OPERATION;
}
if (pHPF->Mh !=0&&pHPF->Mh !=Mo->Mh) {
Mr MA_INVALID_OPERATION;
}
pHPF->format=Mo->format;
pHPF->Mh=Mo->Mh;
a=ma_expd(-2*MA_PI_D*Mo->cutoffFrequency / Mo->sampleRate);
if (Mo->format==ma_format_f32) {
pHPF->a.f32=(float)a;
} else {
pHPF->a.s32=ma_biquad_float_to_fp(a);
}
Mr Ms;
}
static MA_INLINE Mv ma_hpf1_process_pcm_frame_f32(ma_hpf1*pHPF,float*pY,const float*pX)
{
M3 c;
const M3 Mh=pHPF->Mh;
const float a=1-pHPF->a.f32;
const float b=1-a;
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
float r1=pHPF->pR1[c].f32;
float x=pX[c];
float y;
y=b*x-a*r1;
pY[c]=y;
pHPF->pR1[c].f32=y;
}
}
static MA_INLINE Mv ma_hpf1_process_pcm_frame_s16(ma_hpf1*pHPF,ma_int16*pY,const ma_int16*pX)
{
M3 c;
const M3 Mh=pHPF->Mh;
const ma_int32 a=((1<<MA_BIQUAD_FIXED_POINT_SHIFT)-pHPF->a.s32);
const ma_int32 b=((1<<MA_BIQUAD_FIXED_POINT_SHIFT)-a);
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
ma_int32 r1=pHPF->pR1[c].s32;
ma_int32 x=pX[c];
ma_int32 y;
y=(b*x-a*r1)>>MA_BIQUAD_FIXED_POINT_SHIFT;
pY[c]=(ma_int16)y;
pHPF->pR1[c].s32=(ma_int32)y;
}
}
MA_API Me ma_hpf1_process_pcm_frames(ma_hpf1*pHPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
M3 n;
if (pHPF==NULL||pFramesOut==NULL||pFramesIn==NULL) {
Mr MA_INVALID_ARGS;
}
if (pHPF->format==ma_format_f32) { float*pY=( float*)pFramesOut;
const float*pX=(const float*)pFramesIn;
for (n=0; n<frameCount; n+=1) {
ma_hpf1_process_pcm_frame_f32(pHPF,pY,pX);
pY+=pHPF->Mh;
pX+=pHPF->Mh;
}
} else if (pHPF->format==ma_format_s16) { ma_int16*pY=( ma_int16*)pFramesOut;
const ma_int16*pX=(const ma_int16*)pFramesIn;
for (n=0; n<frameCount; n+=1) {
ma_hpf1_process_pcm_frame_s16(pHPF,pY,pX);
pY+=pHPF->Mh;
pX+=pHPF->Mh;
}
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
Mr Ms;
}
MA_API M3 ma_hpf1_get_latency(const ma_hpf1*pHPF)
{
if (pHPF==NULL) {
Mr 0;
}
Mr 1;
}
static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_config*Mo)
{
ma_biquad_config bqConfig;
double q;
double w;
double s;
double c;
double a;
MA_ASSERT(Mo !=NULL);
q=Mo->q;
w=2*MA_PI_D*Mo->cutoffFrequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
a=s / (2*q);
bqConfig.b0=(1+c) / 2;
bqConfig.b1=-(1+c);
bqConfig.b2=(1+c) / 2;
bqConfig.a0=1+a;
bqConfig.a1=-2*c;
bqConfig.a2=1-a;
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_hpf2_get_heap_size(const ma_hpf2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_hpf2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_hpf2_init_preallocated(const ma_hpf2_config*Mo,Mv*pHeap,ma_hpf2*pHPF)
{
Me Mf;
ma_biquad_config bqConfig;
if (pHPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pHPF);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_hpf2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pHPF->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_hpf2_init(const ma_hpf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hpf2*pHPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_hpf2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_hpf2_init_preallocated(Mo,pHeap,pHPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pHPF->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_hpf2_uninit(ma_hpf2*pHPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pHPF==NULL) {
Mr;
}
ma_biquad_uninit(&pHPF->bq,pAllocationCallbacks);
}
MA_API Me ma_hpf2_reinit(const ma_hpf2_config*Mo,ma_hpf2*pHPF)
{
Me Mf;
ma_biquad_config bqConfig;
if (pHPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_hpf2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pHPF->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static MA_INLINE Mv ma_hpf2_process_pcm_frame_s16(ma_hpf2*pHPF,ma_int16*pFrameOut,const ma_int16*pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pHPF->bq,pFrameOut,pFrameIn);
}
static MA_INLINE Mv ma_hpf2_process_pcm_frame_f32(ma_hpf2*pHPF,float*pFrameOut,const float*pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pHPF->bq,pFrameOut,pFrameIn);
}
MA_API Me ma_hpf2_process_pcm_frames(ma_hpf2*pHPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pHPF==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pHPF->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_hpf2_get_latency(const ma_hpf2*pHPF)
{
if (pHPF==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pHPF->bq);
}
MA_API ma_hpf_config ma_hpf_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,M3 order)
{
ma_hpf_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.order=ma_min(order,MA_MAX_FILTER_ORDER);
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t hpf1Offset;
size_t hpf2Offset;
} ma_hpf_heap_layout;
static Mv ma_hpf_calculate_sub_hpf_counts(M3 order,M3*pHPF1Count,M3*pHPF2Count)
{
MA_ASSERT(pHPF1Count !=NULL);
MA_ASSERT(pHPF2Count !=NULL);
*pHPF1Count=order % 2;
*pHPF2Count=order / 2;
}
static Me ma_hpf_get_heap_layout(const ma_hpf_config*Mo,ma_hpf_heap_layout*pHeapLayout)
{
Me Mf;
M3 hpf1Count;
M3 hpf2Count;
M3 ihpf1;
M3 ihpf2;
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
if (Mo->order>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
ma_hpf_calculate_sub_hpf_counts(Mo->order,&hpf1Count,&hpf2Count);
pHeapLayout->sizeInBytes=0;
pHeapLayout->hpf1Offset=pHeapLayout->sizeInBytes;
for (ihpf1=0; ihpf1<hpf1Count; ihpf1+=1) {
size_t hpf1HeapSizeInBytes;
ma_hpf1_config hpf1Config=ma_hpf1_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency);
Mf=ma_hpf1_get_heap_size(&hpf1Config,&hpf1HeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=sizeof(ma_hpf1)+hpf1HeapSizeInBytes;
}
pHeapLayout->hpf2Offset=pHeapLayout->sizeInBytes;
for (ihpf2=0; ihpf2<hpf2Count; ihpf2+=1) {
size_t hpf2HeapSizeInBytes;
ma_hpf2_config hpf2Config=ma_hpf2_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency,0.707107);
Mf=ma_hpf2_get_heap_size(&hpf2Config,&hpf2HeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=sizeof(ma_hpf2)+hpf2HeapSizeInBytes;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
static Me ma_hpf_reinit__internal(const ma_hpf_config*Mo,Mv*pHeap,ma_hpf*pHPF,ma_bool32 isNew)
{
Me Mf;
M3 hpf1Count;
M3 hpf2Count;
M3 ihpf1;
M3 ihpf2;
ma_hpf_heap_layout heapLayout;
if (pHPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (pHPF->format !=ma_format_unknown&&pHPF->format !=Mo->format) {
Mr MA_INVALID_OPERATION;
}
if (pHPF->Mh !=0&&pHPF->Mh !=Mo->Mh) {
Mr MA_INVALID_OPERATION;
}
if (Mo->order>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
ma_hpf_calculate_sub_hpf_counts(Mo->order,&hpf1Count,&hpf2Count);
if (!isNew) {
if (pHPF->hpf1Count !=hpf1Count||pHPF->hpf2Count !=hpf2Count) {
Mr MA_INVALID_OPERATION;
}
}
if (isNew) {
Mf=ma_hpf_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pHPF->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pHPF->pHPF1=(ma_hpf1*)ma_offset_ptr(pHeap,heapLayout.hpf1Offset);
pHPF->pHPF2=(ma_hpf2*)ma_offset_ptr(pHeap,heapLayout.hpf2Offset);
} else {
MA_ZERO_OBJECT(&heapLayout);
}
for (ihpf1=0; ihpf1<hpf1Count; ihpf1+=1) {
ma_hpf1_config hpf1Config=ma_hpf1_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency);
if (isNew) {
size_t hpf1HeapSizeInBytes;
Mf=ma_hpf1_get_heap_size(&hpf1Config,&hpf1HeapSizeInBytes);
if (Mf==Ms) {
Mf=ma_hpf1_init_preallocated(&hpf1Config,ma_offset_ptr(pHeap,heapLayout.hpf1Offset+(sizeof(ma_hpf1)*hpf1Count)+(ihpf1*hpf1HeapSizeInBytes)),&pHPF->pHPF1[ihpf1]);
}
} else {
Mf=ma_hpf1_reinit(&hpf1Config,&pHPF->pHPF1[ihpf1]);
}
if (Mf !=Ms) {
M3 jhpf1;
for (jhpf1=0; jhpf1<ihpf1; jhpf1+=1) {
ma_hpf1_uninit(&pHPF->pHPF1[jhpf1],NULL);
}
Mr Mf;
}
}
for (ihpf2=0; ihpf2<hpf2Count; ihpf2+=1) {
ma_hpf2_config hpf2Config;
double q;
double a;
if (hpf1Count==1) {
a=(1+ihpf2*1)*(MA_PI_D/(Mo->order*1));
} else {
a=(1+ihpf2*2)*(MA_PI_D/(Mo->order*2));
}
q=1 / (2*ma_cosd(a));
hpf2Config=ma_hpf2_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency,q);
if (isNew) {
size_t hpf2HeapSizeInBytes;
Mf=ma_hpf2_get_heap_size(&hpf2Config,&hpf2HeapSizeInBytes);
if (Mf==Ms) {
Mf=ma_hpf2_init_preallocated(&hpf2Config,ma_offset_ptr(pHeap,heapLayout.hpf2Offset+(sizeof(ma_hpf2)*hpf2Count)+(ihpf2*hpf2HeapSizeInBytes)),&pHPF->pHPF2[ihpf2]);
}
} else {
Mf=ma_hpf2_reinit(&hpf2Config,&pHPF->pHPF2[ihpf2]);
}
if (Mf !=Ms) {
M3 jhpf1;
M3 jhpf2;
for (jhpf1=0; jhpf1<hpf1Count; jhpf1+=1) {
ma_hpf1_uninit(&pHPF->pHPF1[jhpf1],NULL);
}
for (jhpf2=0; jhpf2<ihpf2; jhpf2+=1) {
ma_hpf2_uninit(&pHPF->pHPF2[jhpf2],NULL);
}
Mr Mf;
}
}
pHPF->hpf1Count=hpf1Count;
pHPF->hpf2Count=hpf2Count;
pHPF->format=Mo->format;
pHPF->Mh=Mo->Mh;
pHPF->sampleRate=Mo->sampleRate;
Mr Ms;
}
MA_API Me ma_hpf_get_heap_size(const ma_hpf_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_hpf_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_hpf_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Mf;
}
MA_API Me ma_hpf_init_preallocated(const ma_hpf_config*Mo,Mv*pHeap,ma_hpf*pLPF)
{
if (pLPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLPF);
Mr ma_hpf_reinit__internal(Mo,pHeap,pLPF,MA_TRUE);
}
MA_API Me ma_hpf_init(const ma_hpf_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hpf*pHPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_hpf_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_hpf_init_preallocated(Mo,pHeap,pHPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pHPF->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_hpf_uninit(ma_hpf*pHPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
M3 ihpf1;
M3 ihpf2;
if (pHPF==NULL) {
Mr;
}
for (ihpf1=0; ihpf1<pHPF->hpf1Count; ihpf1+=1) {
ma_hpf1_uninit(&pHPF->pHPF1[ihpf1],pAllocationCallbacks);
}
for (ihpf2=0; ihpf2<pHPF->hpf2Count; ihpf2+=1) {
ma_hpf2_uninit(&pHPF->pHPF2[ihpf2],pAllocationCallbacks);
}
if (pHPF->_ownsHeap) {
ma_free(pHPF->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_hpf_reinit(const ma_hpf_config*Mo,ma_hpf*pHPF)
{
Mr ma_hpf_reinit__internal(Mo,NULL,pHPF,MA_FALSE);
}
MA_API Me ma_hpf_process_pcm_frames(ma_hpf*pHPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
Me Mf;
M3 ihpf1;
M3 ihpf2;
if (pHPF==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFramesOut==pFramesIn) {
for (ihpf1=0; ihpf1<pHPF->hpf1Count; ihpf1+=1) {
Mf=ma_hpf1_process_pcm_frames(&pHPF->pHPF1[ihpf1],pFramesOut,pFramesOut,frameCount);
if (Mf !=Ms) {
Mr Mf;
}
}
for (ihpf2=0; ihpf2<pHPF->hpf2Count; ihpf2+=1) {
Mf=ma_hpf2_process_pcm_frames(&pHPF->pHPF2[ihpf2],pFramesOut,pFramesOut,frameCount);
if (Mf !=Ms) {
Mr Mf;
}
}
}
if (pFramesOut !=pFramesIn) {
M3 iFrame; if (pHPF->format==ma_format_f32) { float*pFramesOutF32=( float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
MA_COPY_MEMORY(pFramesOutF32,pFramesInF32,ma_get_bytes_per_frame(pHPF->format,pHPF->Mh));
for (ihpf1=0; ihpf1<pHPF->hpf1Count; ihpf1+=1) {
 ma_hpf1_process_pcm_frame_f32(&pHPF->pHPF1[ihpf1],pFramesOutF32,pFramesOutF32);
}
for (ihpf2=0; ihpf2<pHPF->hpf2Count; ihpf2+=1) {
 ma_hpf2_process_pcm_frame_f32(&pHPF->pHPF2[ihpf2],pFramesOutF32,pFramesOutF32);
}
pFramesOutF32+=pHPF->Mh;
pFramesInF32+=pHPF->Mh;
}
} else if (pHPF->format==ma_format_s16) { ma_int16*pFramesOutS16=( ma_int16*)pFramesOut;
const ma_int16*pFramesInS16=(const ma_int16*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
MA_COPY_MEMORY(pFramesOutS16,pFramesInS16,ma_get_bytes_per_frame(pHPF->format,pHPF->Mh));
for (ihpf1=0; ihpf1<pHPF->hpf1Count; ihpf1+=1) {
 ma_hpf1_process_pcm_frame_s16(&pHPF->pHPF1[ihpf1],pFramesOutS16,pFramesOutS16);
}
for (ihpf2=0; ihpf2<pHPF->hpf2Count; ihpf2+=1) {
 ma_hpf2_process_pcm_frame_s16(&pHPF->pHPF2[ihpf2],pFramesOutS16,pFramesOutS16);
}
pFramesOutS16+=pHPF->Mh;
pFramesInS16+=pHPF->Mh;
}
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_OPERATION;
}
}
Mr Ms;
}
MA_API M3 ma_hpf_get_latency(const ma_hpf*pHPF)
{
if (pHPF==NULL) {
Mr 0;
}
Mr pHPF->hpf2Count*2+pHPF->hpf1Count;
}
MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,double q)
{
ma_bpf2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.q=q;
if (config.q==0) {
config.q=0.707107;
}
Mr config;
}
static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_config*Mo)
{
ma_biquad_config bqConfig;
double q;
double w;
double s;
double c;
double a;
MA_ASSERT(Mo !=NULL);
q=Mo->q;
w=2*MA_PI_D*Mo->cutoffFrequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
a=s / (2*q);
bqConfig.b0=q*a;
bqConfig.b1=0;
bqConfig.b2=-q*a;
bqConfig.a0=1+a;
bqConfig.a1=-2*c;
bqConfig.a2=1-a;
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_bpf2_get_heap_size(const ma_bpf2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_bpf2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_bpf2_init_preallocated(const ma_bpf2_config*Mo,Mv*pHeap,ma_bpf2*pBPF)
{
Me Mf;
ma_biquad_config bqConfig;
if (pBPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pBPF);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_bpf2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pBPF->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_bpf2_init(const ma_bpf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_bpf2*pBPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_bpf2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_bpf2_init_preallocated(Mo,pHeap,pBPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pBPF->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_bpf2_uninit(ma_bpf2*pBPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pBPF==NULL) {
Mr;
}
ma_biquad_uninit(&pBPF->bq,pAllocationCallbacks);
}
MA_API Me ma_bpf2_reinit(const ma_bpf2_config*Mo,ma_bpf2*pBPF)
{
Me Mf;
ma_biquad_config bqConfig;
if (pBPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_bpf2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pBPF->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static MA_INLINE Mv ma_bpf2_process_pcm_frame_s16(ma_bpf2*pBPF,ma_int16*pFrameOut,const ma_int16*pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pBPF->bq,pFrameOut,pFrameIn);
}
static MA_INLINE Mv ma_bpf2_process_pcm_frame_f32(ma_bpf2*pBPF,float*pFrameOut,const float*pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pBPF->bq,pFrameOut,pFrameIn);
}
MA_API Me ma_bpf2_process_pcm_frames(ma_bpf2*pBPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pBPF==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pBPF->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_bpf2_get_latency(const ma_bpf2*pBPF)
{
if (pBPF==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pBPF->bq);
}
MA_API ma_bpf_config ma_bpf_config_init(ma_format format,M3 Mh,M3 sampleRate,double cutoffFrequency,M3 order)
{
ma_bpf_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.cutoffFrequency=cutoffFrequency;
config.order=ma_min(order,MA_MAX_FILTER_ORDER);
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t bpf2Offset;
} ma_bpf_heap_layout;
static Me ma_bpf_get_heap_layout(const ma_bpf_config*Mo,ma_bpf_heap_layout*pHeapLayout)
{
Me Mf;
M3 bpf2Count;
M3 ibpf2;
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->order>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
if ((Mo->order&0x1) !=0) {
Mr MA_INVALID_ARGS;
}
bpf2Count=Mo->order / 2;
pHeapLayout->sizeInBytes=0;
pHeapLayout->bpf2Offset=pHeapLayout->sizeInBytes;
for (ibpf2=0; ibpf2<bpf2Count; ibpf2+=1) {
size_t bpf2HeapSizeInBytes;
ma_bpf2_config bpf2Config=ma_bpf2_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency,0.707107);
Mf=ma_bpf2_get_heap_size(&bpf2Config,&bpf2HeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=sizeof(ma_bpf2)+bpf2HeapSizeInBytes;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
static Me ma_bpf_reinit__internal(const ma_bpf_config*Mo,Mv*pHeap,ma_bpf*pBPF,ma_bool32 isNew)
{
Me Mf;
M3 bpf2Count;
M3 ibpf2;
ma_bpf_heap_layout heapLayout;
if (pBPF==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (pBPF->format !=ma_format_unknown&&pBPF->format !=Mo->format) {
Mr MA_INVALID_OPERATION;
}
if (pBPF->Mh !=0&&pBPF->Mh !=Mo->Mh) {
Mr MA_INVALID_OPERATION;
}
if (Mo->order>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
if ((Mo->order&0x1) !=0) {
Mr MA_INVALID_ARGS;
}
bpf2Count=Mo->order / 2;
if (!isNew) {
if (pBPF->bpf2Count !=bpf2Count) {
Mr MA_INVALID_OPERATION;
}
}
if (isNew) {
Mf=ma_bpf_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pBPF->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pBPF->pBPF2=(ma_bpf2*)ma_offset_ptr(pHeap,heapLayout.bpf2Offset);
} else {
MA_ZERO_OBJECT(&heapLayout);
}
for (ibpf2=0; ibpf2<bpf2Count; ibpf2+=1) {
ma_bpf2_config bpf2Config;
double q;
q=0.707107;
bpf2Config=ma_bpf2_config_init(Mo->format,Mo->Mh,Mo->sampleRate,Mo->cutoffFrequency,q);
if (isNew) {
size_t bpf2HeapSizeInBytes;
Mf=ma_bpf2_get_heap_size(&bpf2Config,&bpf2HeapSizeInBytes);
if (Mf==Ms) {
Mf=ma_bpf2_init_preallocated(&bpf2Config,ma_offset_ptr(pHeap,heapLayout.bpf2Offset+(sizeof(ma_bpf2)*bpf2Count)+(ibpf2*bpf2HeapSizeInBytes)),&pBPF->pBPF2[ibpf2]);
}
} else {
Mf=ma_bpf2_reinit(&bpf2Config,&pBPF->pBPF2[ibpf2]);
}
if (Mf !=Ms) {
Mr Mf;
}
}
pBPF->bpf2Count=bpf2Count;
pBPF->format=Mo->format;
pBPF->Mh=Mo->Mh;
Mr Ms;
}
MA_API Me ma_bpf_get_heap_size(const ma_bpf_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_bpf_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_bpf_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_bpf_init_preallocated(const ma_bpf_config*Mo,Mv*pHeap,ma_bpf*pBPF)
{
if (pBPF==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pBPF);
Mr ma_bpf_reinit__internal(Mo,pHeap,pBPF,MA_TRUE);
}
MA_API Me ma_bpf_init(const ma_bpf_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_bpf*pBPF)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_bpf_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_bpf_init_preallocated(Mo,pHeap,pBPF);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pBPF->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_bpf_uninit(ma_bpf*pBPF,const ma_allocation_callbacks*pAllocationCallbacks)
{
M3 ibpf2;
if (pBPF==NULL) {
Mr;
}
for (ibpf2=0; ibpf2<pBPF->bpf2Count; ibpf2+=1) {
ma_bpf2_uninit(&pBPF->pBPF2[ibpf2],pAllocationCallbacks);
}
if (pBPF->_ownsHeap) {
ma_free(pBPF->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_bpf_reinit(const ma_bpf_config*Mo,ma_bpf*pBPF)
{
Mr ma_bpf_reinit__internal(Mo,NULL,pBPF,MA_FALSE);
}
MA_API Me ma_bpf_process_pcm_frames(ma_bpf*pBPF,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
Me Mf;
M3 ibpf2;
if (pBPF==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFramesOut==pFramesIn) {
for (ibpf2=0; ibpf2<pBPF->bpf2Count; ibpf2+=1) {
Mf=ma_bpf2_process_pcm_frames(&pBPF->pBPF2[ibpf2],pFramesOut,pFramesOut,frameCount);
if (Mf !=Ms) {
Mr Mf;
}
}
}
if (pFramesOut !=pFramesIn) {
M3 iFrame; if (pBPF->format==ma_format_f32) { float*pFramesOutF32=( float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
MA_COPY_MEMORY(pFramesOutF32,pFramesInF32,ma_get_bytes_per_frame(pBPF->format,pBPF->Mh));
for (ibpf2=0; ibpf2<pBPF->bpf2Count; ibpf2+=1) {
 ma_bpf2_process_pcm_frame_f32(&pBPF->pBPF2[ibpf2],pFramesOutF32,pFramesOutF32);
}
pFramesOutF32+=pBPF->Mh;
pFramesInF32+=pBPF->Mh;
}
} else if (pBPF->format==ma_format_s16) { ma_int16*pFramesOutS16=( ma_int16*)pFramesOut;
const ma_int16*pFramesInS16=(const ma_int16*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
MA_COPY_MEMORY(pFramesOutS16,pFramesInS16,ma_get_bytes_per_frame(pBPF->format,pBPF->Mh));
for (ibpf2=0; ibpf2<pBPF->bpf2Count; ibpf2+=1) {
 ma_bpf2_process_pcm_frame_s16(&pBPF->pBPF2[ibpf2],pFramesOutS16,pFramesOutS16);
}
pFramesOutS16+=pBPF->Mh;
pFramesInS16+=pBPF->Mh;
}
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_OPERATION;
}
}
Mr Ms;
}
MA_API M3 ma_bpf_get_latency(const ma_bpf*pBPF)
{
if (pBPF==NULL) {
Mr 0;
}
Mr pBPF->bpf2Count*2;
}
MA_API ma_notch2_config ma_notch2_config_init(ma_format format,M3 Mh,M3 sampleRate,double q,double frequency)
{
ma_notch2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.q=q;
config.frequency=frequency;
if (config.q==0) {
config.q=0.707107;
}
Mr config;
}
static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_config*Mo)
{
ma_biquad_config bqConfig;
double q;
double w;
double s;
double c;
double a;
MA_ASSERT(Mo !=NULL);
q=Mo->q;
w=2*MA_PI_D*Mo->frequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
a=s / (2*q);
bqConfig.b0=1;
bqConfig.b1=-2*c;
bqConfig.b2=1;
bqConfig.a0=1+a;
bqConfig.a1=-2*c;
bqConfig.a2=1-a;
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_notch2_get_heap_size(const ma_notch2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_notch2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_notch2_init_preallocated(const ma_notch2_config*Mo,Mv*pHeap,ma_notch2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFilter);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_notch2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_notch2_init(const ma_notch2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_notch2*pFilter)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_notch2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_notch2_init_preallocated(Mo,pHeap,pFilter);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pFilter->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_notch2_uninit(ma_notch2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pFilter==NULL) {
Mr;
}
ma_biquad_uninit(&pFilter->bq,pAllocationCallbacks);
}
MA_API Me ma_notch2_reinit(const ma_notch2_config*Mo,ma_notch2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_notch2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static MA_INLINE Mv ma_notch2_process_pcm_frame_s16(ma_notch2*pFilter,ma_int16*pFrameOut,const ma_int16*pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pFilter->bq,pFrameOut,pFrameIn);
}
static MA_INLINE Mv ma_notch2_process_pcm_frame_f32(ma_notch2*pFilter,float*pFrameOut,const float*pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pFilter->bq,pFrameOut,pFrameIn);
}
MA_API Me ma_notch2_process_pcm_frames(ma_notch2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pFilter->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_notch2_get_latency(const ma_notch2*pFilter)
{
if (pFilter==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pFilter->bq);
}
MA_API ma_peak2_config ma_peak2_config_init(ma_format format,M3 Mh,M3 sampleRate,double gainDB,double q,double frequency)
{
ma_peak2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.gainDB=gainDB;
config.q=q;
config.frequency=frequency;
if (config.q==0) {
config.q=0.707107;
}
Mr config;
}
static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_config*Mo)
{
ma_biquad_config bqConfig;
double q;
double w;
double s;
double c;
double a;
double A;
MA_ASSERT(Mo !=NULL);
q=Mo->q;
w=2*MA_PI_D*Mo->frequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
a=s / (2*q);
A=ma_powd(10,(Mo->gainDB / 40));
bqConfig.b0=1+(a*A);
bqConfig.b1=-2*c;
bqConfig.b2=1-(a*A);
bqConfig.a0=1+(a / A);
bqConfig.a1=-2*c;
bqConfig.a2=1-(a / A);
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_peak2_get_heap_size(const ma_peak2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_peak2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_peak2_init_preallocated(const ma_peak2_config*Mo,Mv*pHeap,ma_peak2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFilter);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_peak2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_peak2_init(const ma_peak2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_peak2*pFilter)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_peak2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_peak2_init_preallocated(Mo,pHeap,pFilter);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pFilter->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_peak2_uninit(ma_peak2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pFilter==NULL) {
Mr;
}
ma_biquad_uninit(&pFilter->bq,pAllocationCallbacks);
}
MA_API Me ma_peak2_reinit(const ma_peak2_config*Mo,ma_peak2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_peak2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static MA_INLINE Mv ma_peak2_process_pcm_frame_s16(ma_peak2*pFilter,ma_int16*pFrameOut,const ma_int16*pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pFilter->bq,pFrameOut,pFrameIn);
}
static MA_INLINE Mv ma_peak2_process_pcm_frame_f32(ma_peak2*pFilter,float*pFrameOut,const float*pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pFilter->bq,pFrameOut,pFrameIn);
}
MA_API Me ma_peak2_process_pcm_frames(ma_peak2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pFilter->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_peak2_get_latency(const ma_peak2*pFilter)
{
if (pFilter==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pFilter->bq);
}
MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double gainDB,double shelfSlope,double frequency)
{
ma_loshelf2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.gainDB=gainDB;
config.shelfSlope=shelfSlope;
config.frequency=frequency;
Mr config;
}
static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshelf2_config*Mo)
{
ma_biquad_config bqConfig;
double w;
double s;
double c;
double A;
double S;
double a;
double sqrtA;
MA_ASSERT(Mo !=NULL);
w=2*MA_PI_D*Mo->frequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
A=ma_powd(10,(Mo->gainDB / 40));
S=Mo->shelfSlope;
a=s/2*ma_sqrtd((A+1/A)*(1/S-1)+2);
sqrtA=2*ma_sqrtd(A)*a;
bqConfig.b0=A*((A+1)-(A-1)*c+sqrtA);
bqConfig.b1=2*A*((A-1)-(A+1)*c);
bqConfig.b2=A*((A+1)-(A-1)*c-sqrtA);
bqConfig.a0=(A+1)+(A-1)*c+sqrtA;
bqConfig.a1=-2*((A-1)+(A+1)*c);
bqConfig.a2=(A+1)+(A-1)*c-sqrtA;
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_loshelf2_get_heap_size(const ma_loshelf2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_loshelf2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_loshelf2_init_preallocated(const ma_loshelf2_config*Mo,Mv*pHeap,ma_loshelf2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFilter);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_loshelf2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_loshelf2_init(const ma_loshelf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_loshelf2*pFilter)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_loshelf2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_loshelf2_init_preallocated(Mo,pHeap,pFilter);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pFilter->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_loshelf2_uninit(ma_loshelf2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pFilter==NULL) {
Mr;
}
ma_biquad_uninit(&pFilter->bq,pAllocationCallbacks);
}
MA_API Me ma_loshelf2_reinit(const ma_loshelf2_config*Mo,ma_loshelf2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_loshelf2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static MA_INLINE Mv ma_loshelf2_process_pcm_frame_s16(ma_loshelf2*pFilter,ma_int16*pFrameOut,const ma_int16*pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pFilter->bq,pFrameOut,pFrameIn);
}
static MA_INLINE Mv ma_loshelf2_process_pcm_frame_f32(ma_loshelf2*pFilter,float*pFrameOut,const float*pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pFilter->bq,pFrameOut,pFrameIn);
}
MA_API Me ma_loshelf2_process_pcm_frames(ma_loshelf2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pFilter->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_loshelf2_get_latency(const ma_loshelf2*pFilter)
{
if (pFilter==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pFilter->bq);
}
MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format,M3 Mh,M3 sampleRate,double gainDB,double shelfSlope,double frequency)
{
ma_hishelf2_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
config.gainDB=gainDB;
config.shelfSlope=shelfSlope;
config.frequency=frequency;
Mr config;
}
static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishelf2_config*Mo)
{
ma_biquad_config bqConfig;
double w;
double s;
double c;
double A;
double S;
double a;
double sqrtA;
MA_ASSERT(Mo !=NULL);
w=2*MA_PI_D*Mo->frequency / Mo->sampleRate;
s=ma_sind(w);
c=ma_cosd(w);
A=ma_powd(10,(Mo->gainDB / 40));
S=Mo->shelfSlope;
a=s/2*ma_sqrtd((A+1/A)*(1/S-1)+2);
sqrtA=2*ma_sqrtd(A)*a;
bqConfig.b0=A*((A+1)+(A-1)*c+sqrtA);
bqConfig.b1=-2*A*((A-1)+(A+1)*c);
bqConfig.b2=A*((A+1)+(A-1)*c-sqrtA);
bqConfig.a0=(A+1)-(A-1)*c+sqrtA;
bqConfig.a1=2*((A-1)-(A+1)*c);
bqConfig.a2=(A+1)-(A-1)*c-sqrtA;
bqConfig.format=Mo->format;
bqConfig.Mh=Mo->Mh;
Mr bqConfig;
}
MA_API Me ma_hishelf2_get_heap_size(const ma_hishelf2_config*Mo,size_t*pHeapSizeInBytes)
{
ma_biquad_config bqConfig;
bqConfig=ma_hishelf2__get_biquad_config(Mo);
Mr ma_biquad_get_heap_size(&bqConfig,pHeapSizeInBytes);
}
MA_API Me ma_hishelf2_init_preallocated(const ma_hishelf2_config*Mo,Mv*pHeap,ma_hishelf2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFilter);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_hishelf2__get_biquad_config(Mo);
Mf=ma_biquad_init_preallocated(&bqConfig,pHeap,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_hishelf2_init(const ma_hishelf2_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_hishelf2*pFilter)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_hishelf2_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_hishelf2_init_preallocated(Mo,pHeap,pFilter);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pFilter->bq._ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_hishelf2_uninit(ma_hishelf2*pFilter,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pFilter==NULL) {
Mr;
}
ma_biquad_uninit(&pFilter->bq,pAllocationCallbacks);
}
MA_API Me ma_hishelf2_reinit(const ma_hishelf2_config*Mo,ma_hishelf2*pFilter)
{
Me Mf;
ma_biquad_config bqConfig;
if (pFilter==NULL||Mo==NULL) {
Mr MA_INVALID_ARGS;
}
bqConfig=ma_hishelf2__get_biquad_config(Mo);
Mf=ma_biquad_reinit(&bqConfig,&pFilter->bq);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
static MA_INLINE Mv 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 Mv 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 Me ma_hishelf2_process_pcm_frames(ma_hishelf2*pFilter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pFilter==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_biquad_process_pcm_frames(&pFilter->bq,pFramesOut,pFramesIn,frameCount);
}
MA_API M3 ma_hishelf2_get_latency(const ma_hishelf2*pFilter)
{
if (pFilter==NULL) {
Mr 0;
}
Mr ma_biquad_get_latency(&pFilter->bq);
}
MA_API ma_delay_config ma_delay_config_init(M3 Mh,M3 sampleRate,M3 delayInFrames,float decay)
{
ma_delay_config config;
MA_ZERO_OBJECT(&config);
config.Mh=Mh;
config.sampleRate=sampleRate;
config.delayInFrames=delayInFrames;
config.delayStart=(decay==0)?MA_TRUE:MA_FALSE;
config.wet=1;
config.dry=1;
config.decay=decay;
Mr config;
}
MA_API Me ma_delay_init(const ma_delay_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_delay*pDelay)
{
if (pDelay==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pDelay);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->decay<0||Mo->decay>1) {
Mr MA_INVALID_ARGS;
}
pDelay->config=*Mo;
pDelay->bufferSizeInFrames=Mo->delayInFrames;
pDelay->cursor=0;
pDelay->pBuffer=(float*)ma_malloc((size_t)(pDelay->bufferSizeInFrames*ma_get_bytes_per_frame(ma_format_f32,Mo->Mh)),pAllocationCallbacks);
if (pDelay->pBuffer==NULL) {
Mr MA_OUT_OF_MEMORY;
}
ma_silence_pcm_frames(pDelay->pBuffer,pDelay->bufferSizeInFrames,ma_format_f32,Mo->Mh);
Mr Ms;
}
MA_API Mv ma_delay_uninit(ma_delay*pDelay,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pDelay==NULL) {
Mr;
}
ma_free(pDelay->pBuffer,pAllocationCallbacks);
}
MA_API Me ma_delay_process_pcm_frames(ma_delay*pDelay,Mv*pFramesOut,const Mv*pFramesIn,M3 frameCount)
{
M3 iFrame;
M3 iChannel;
float*pFramesOutF32=(float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
if (pDelay==NULL||pFramesOut==NULL||pFramesIn==NULL) {
Mr MA_INVALID_ARGS;
}
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannel=0; iChannel<pDelay->config.Mh; iChannel+=1) {
M3 iBuffer=(pDelay->cursor*pDelay->config.Mh)+iChannel;
if (pDelay->config.delayStart) {
pFramesOutF32[iChannel]=pDelay->pBuffer[iBuffer]*pDelay->config.wet;
pDelay->pBuffer[iBuffer]=(pDelay->pBuffer[iBuffer]*pDelay->config.decay)+(pFramesInF32[iChannel]*pDelay->config.dry);
} else {
pDelay->pBuffer[iBuffer]=(pDelay->pBuffer[iBuffer]*pDelay->config.decay)+(pFramesInF32[iChannel]*pDelay->config.dry);
pFramesOutF32[iChannel]=pDelay->pBuffer[iBuffer]*pDelay->config.wet;
}
}
pDelay->cursor=(pDelay->cursor+1) % pDelay->bufferSizeInFrames;
pFramesOutF32+=pDelay->config.Mh;
pFramesInF32+=pDelay->config.Mh;
}
Mr Ms;
}
MA_API Mv ma_delay_set_wet(ma_delay*pDelay,float value)
{
if (pDelay==NULL) {
Mr;
}
pDelay->config.wet=value;
}
MA_API float ma_delay_get_wet(const ma_delay*pDelay)
{
if (pDelay==NULL) {
Mr 0;
}
Mr pDelay->config.wet;
}
MA_API Mv ma_delay_set_dry(ma_delay*pDelay,float value)
{
if (pDelay==NULL) {
Mr;
}
pDelay->config.dry=value;
}
MA_API float ma_delay_get_dry(const ma_delay*pDelay)
{
if (pDelay==NULL) {
Mr 0;
}
Mr pDelay->config.dry;
}
MA_API Mv ma_delay_set_decay(ma_delay*pDelay,float value)
{
if (pDelay==NULL) {
Mr;
}
pDelay->config.decay=value;
}
MA_API float ma_delay_get_decay(const ma_delay*pDelay)
{
if (pDelay==NULL) {
Mr 0;
}
Mr pDelay->config.decay;
}
MA_API ma_gainer_config ma_gainer_config_init(M3 Mh,M3 smoothTimeInFrames)
{
ma_gainer_config config;
MA_ZERO_OBJECT(&config);
config.Mh=Mh;
config.smoothTimeInFrames=smoothTimeInFrames;
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t oldGainsOffset;
size_t newGainsOffset;
} ma_gainer_heap_layout;
static Me ma_gainer_get_heap_layout(const ma_gainer_config*Mo,ma_gainer_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->oldGainsOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=sizeof(float)*Mo->Mh;
pHeapLayout->newGainsOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=sizeof(float)*Mo->Mh;
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_gainer_get_heap_size(const ma_gainer_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_gainer_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_gainer_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_gainer_init_preallocated(const ma_gainer_config*Mo,Mv*pHeap,ma_gainer*pGainer)
{
Me Mf;
ma_gainer_heap_layout heapLayout;
M3 iChannel;
if (pGainer==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pGainer);
if (Mo==NULL||pHeap==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_gainer_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pGainer->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pGainer->pOldGains=(float*)ma_offset_ptr(pHeap,heapLayout.oldGainsOffset);
pGainer->pNewGains=(float*)ma_offset_ptr(pHeap,heapLayout.newGainsOffset);
pGainer->masterVolume=1;
pGainer->config=*Mo;
pGainer->t=(M3)-1;
for (iChannel=0; iChannel<Mo->Mh; iChannel+=1) {
pGainer->pOldGains[iChannel]=1;
pGainer->pNewGains[iChannel]=1;
}
Mr Ms;
}
MA_API Me ma_gainer_init(const ma_gainer_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_gainer*pGainer)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_gainer_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_gainer_init_preallocated(Mo,pHeap,pGainer);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pGainer->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_gainer_uninit(ma_gainer*pGainer,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pGainer==NULL) {
Mr;
}
if (pGainer->_ownsHeap) {
ma_free(pGainer->_pHeap,pAllocationCallbacks);
}
}
static float ma_gainer_calculate_current_gain(const ma_gainer*pGainer,M3 channel)
{
float a=(float)pGainer->t / pGainer->config.smoothTimeInFrames;
Mr ma_mix_f32_fast(pGainer->pOldGains[channel],pGainer->pNewGains[channel],a);
}
static Me ma_gainer_process_pcm_frames_internal(ma_gainer*pGainer,Mv*MA_RESTRICT pFramesOut,const Mv*MA_RESTRICT pFramesIn,M6 frameCount)
{
M6 iFrame;
M3 iChannel;
M6 interpolatedFrameCount;
MA_ASSERT(pGainer !=NULL);
if (pGainer->t>=pGainer->config.smoothTimeInFrames) {
interpolatedFrameCount=0;
} else {
interpolatedFrameCount=pGainer->t-pGainer->config.smoothTimeInFrames;
if (interpolatedFrameCount>frameCount) {
interpolatedFrameCount=frameCount;
}
}
if (interpolatedFrameCount>0) {
if (pFramesOut !=NULL&&pFramesIn !=NULL) {
float*pFramesOutF32=(float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
float a=(float)pGainer->t / pGainer->config.smoothTimeInFrames;
float d=1.0f / pGainer->config.smoothTimeInFrames;
if (pGainer->config.Mh<=32) {
float pRunningGain[32];
float pRunningGainDelta[32];
for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
 float t=(pGainer->pNewGains[iChannel]-pGainer->pOldGains[iChannel])*pGainer->masterVolume;
 pRunningGainDelta[iChannel]=t*d;
 pRunningGain[iChannel]=(pGainer->pOldGains[iChannel]*pGainer->masterVolume)+(t*a);
}
iFrame=0;
if (pGainer->config.Mh==2) {
#if defined(MA_SUPPORT_SSE2)
 if (ma_has_sse2()) {
 M6 unrolledLoopCount=interpolatedFrameCount>>1;
 __m128 runningGainDelta0=_mm_set_ps(pRunningGainDelta[1],pRunningGainDelta[0],pRunningGainDelta[1],pRunningGainDelta[0]);
 __m128 runningGain0=_mm_set_ps(pRunningGain[1]+pRunningGainDelta[1],pRunningGain[0]+pRunningGainDelta[0],pRunningGain[1],pRunningGain[0]);
 for (; iFrame<unrolledLoopCount; iFrame+=1) {
 _mm_storeu_ps(&pFramesOutF32[iFrame*4+0],_mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*4+0]),runningGain0));
 runningGain0=_mm_add_ps(runningGain0,runningGainDelta0);
 }
 iFrame=unrolledLoopCount<<1;
 } else
#endif
 {
 #if defined(_MSC_VER)&&!defined(__clang__)
 M6 unrolledLoopCount=interpolatedFrameCount>>1;
 pRunningGainDelta[2]=pRunningGainDelta[0];
 pRunningGainDelta[3]=pRunningGainDelta[1];
 pRunningGain[2]=pRunningGain[0]+pRunningGainDelta[0];
 pRunningGain[3]=pRunningGain[1]+pRunningGainDelta[1];
 for (; iFrame<unrolledLoopCount; iFrame+=1) {
 pFramesOutF32[iFrame*4+0]=pFramesInF32[iFrame*4+0]*pRunningGain[0];
 pFramesOutF32[iFrame*4+1]=pFramesInF32[iFrame*4+1]*pRunningGain[1];
 pFramesOutF32[iFrame*4+2]=pFramesInF32[iFrame*4+2]*pRunningGain[2];
 pFramesOutF32[iFrame*4+3]=pFramesInF32[iFrame*4+3]*pRunningGain[3];
 pRunningGain[0]+=pRunningGainDelta[0];
 pRunningGain[1]+=pRunningGainDelta[1];
 pRunningGain[2]+=pRunningGainDelta[2];
 pRunningGain[3]+=pRunningGainDelta[3];
 }
 iFrame=unrolledLoopCount<<1;
 #else
 for (; iFrame<interpolatedFrameCount; iFrame+=1) {
 for (iChannel=0; iChannel<2; iChannel+=1) {
 pFramesOutF32[iFrame*2+iChannel]=pFramesInF32[iFrame*2+iChannel]*pRunningGain[iChannel];
 }
 for (iChannel=0; iChannel<2; iChannel+=1) {
 pRunningGain[iChannel]+=pRunningGainDelta[iChannel];
 }
 }
 #endif
 }
} else if (pGainer->config.Mh==6) {
#if defined(MA_SUPPORT_SSE2)
 if (ma_has_sse2()) {
 M6 unrolledLoopCount=interpolatedFrameCount>>1;
 __m128 runningGainDelta0=_mm_set_ps(pRunningGainDelta[3],pRunningGainDelta[2],pRunningGainDelta[1],pRunningGainDelta[0]);
 __m128 runningGainDelta1=_mm_set_ps(pRunningGainDelta[1],pRunningGainDelta[0],pRunningGainDelta[5],pRunningGainDelta[4]);
 __m128 runningGainDelta2=_mm_set_ps(pRunningGainDelta[5],pRunningGainDelta[4],pRunningGainDelta[3],pRunningGainDelta[2]);
 __m128 runningGain0=_mm_set_ps(pRunningGain[3],pRunningGain[2],pRunningGain[1],pRunningGain[0]);
 __m128 runningGain1=_mm_set_ps(pRunningGain[1]+pRunningGainDelta[1],pRunningGain[0]+pRunningGainDelta[0],pRunningGain[5],pRunningGain[4]);
 __m128 runningGain2=_mm_set_ps(pRunningGain[5]+pRunningGainDelta[5],pRunningGain[4]+pRunningGainDelta[4],pRunningGain[3]+pRunningGainDelta[3],pRunningGain[2]+pRunningGainDelta[2]);
 for (; iFrame<unrolledLoopCount; iFrame+=1) {
 _mm_storeu_ps(&pFramesOutF32[iFrame*12+0],_mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12+0]),runningGain0));
 _mm_storeu_ps(&pFramesOutF32[iFrame*12+4],_mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12+4]),runningGain1));
 _mm_storeu_ps(&pFramesOutF32[iFrame*12+8],_mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*12+8]),runningGain2));
 runningGain0=_mm_add_ps(runningGain0,runningGainDelta0);
 runningGain1=_mm_add_ps(runningGain1,runningGainDelta1);
 runningGain2=_mm_add_ps(runningGain2,runningGainDelta2);
 }
 iFrame=unrolledLoopCount<<1;
 } else
#endif
 {
 for (; iFrame<interpolatedFrameCount; iFrame+=1) {
 for (iChannel=0; iChannel<6; iChannel+=1) {
 pFramesOutF32[iFrame*6+iChannel]=pFramesInF32[iFrame*6+iChannel]*pRunningGain[iChannel];
 }
 for (iChannel=0; iChannel<6; iChannel+=1) {
 pRunningGain[iChannel]+=pRunningGainDelta[iChannel];
 }
 }
 }
} else if (pGainer->config.Mh==8) {
#if defined(MA_SUPPORT_SSE2)
 if (ma_has_sse2()) {
 __m128 runningGainDelta0=_mm_loadu_ps(&pRunningGainDelta[0]);
 __m128 runningGainDelta1=_mm_loadu_ps(&pRunningGainDelta[4]);
 __m128 runningGain0=_mm_loadu_ps(&pRunningGain[0]);
 __m128 runningGain1=_mm_loadu_ps(&pRunningGain[4]);
 for (; iFrame<interpolatedFrameCount; iFrame+=1) {
 _mm_storeu_ps(&pFramesOutF32[iFrame*8+0],_mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*8+0]),runningGain0));
 _mm_storeu_ps(&pFramesOutF32[iFrame*8+4],_mm_mul_ps(_mm_loadu_ps(&pFramesInF32[iFrame*8+4]),runningGain1));
 runningGain0=_mm_add_ps(runningGain0,runningGainDelta0);
 runningGain1=_mm_add_ps(runningGain1,runningGainDelta1);
 }
 } else
#endif
 {
 for (; iFrame<interpolatedFrameCount; iFrame+=1) {
 for (iChannel=0; iChannel<8; iChannel+=1) {
 pFramesOutF32[iFrame*8+iChannel]=pFramesInF32[iFrame*8+iChannel]*pRunningGain[iChannel];
 }
 for (iChannel=0; iChannel<8; iChannel+=1) {
 pRunningGain[iChannel]+=pRunningGainDelta[iChannel];
 }
 }
 }
}
for (; iFrame<interpolatedFrameCount; iFrame+=1) {
 for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
 pFramesOutF32[iFrame*pGainer->config.Mh+iChannel]=pFramesInF32[iFrame*pGainer->config.Mh+iChannel]*pRunningGain[iChannel];
 pRunningGain[iChannel]+=pRunningGainDelta[iChannel];
 }
}
} else {
for (iFrame=0; iFrame<interpolatedFrameCount; iFrame+=1) {
 for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
 pFramesOutF32[iFrame*pGainer->config.Mh+iChannel]=pFramesInF32[iFrame*pGainer->config.Mh+iChannel]*ma_mix_f32_fast(pGainer->pOldGains[iChannel],pGainer->pNewGains[iChannel],a)*pGainer->masterVolume;
 }
 a+=d;
}
}
}
pGainer->t=(M3)ma_min(pGainer->t+interpolatedFrameCount,pGainer->config.smoothTimeInFrames);
frameCount-=interpolatedFrameCount;
pFramesOut=ma_offset_ptr(pFramesOut,interpolatedFrameCount*sizeof(float));
pFramesIn=ma_offset_ptr(pFramesIn,interpolatedFrameCount*sizeof(float));
}
if (pFramesOut !=NULL&&pFramesIn !=NULL) {
if (pGainer->config.Mh<=32) {
float gains[32];
for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
gains[iChannel]=pGainer->pNewGains[iChannel]*pGainer->masterVolume;
}
ma_copy_and_apply_volume_factor_per_channel_f32((float*)pFramesOut,(const float*)pFramesIn,frameCount,pGainer->config.Mh,gains);
} else {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
 ((float*)pFramesOut)[iFrame*pGainer->config.Mh+iChannel]=((const float*)pFramesIn)[iFrame*pGainer->config.Mh+iChannel]*pGainer->pNewGains[iChannel]*pGainer->masterVolume;
}
}
}
}
if (pGainer->t==(M3)-1) {
pGainer->t=(M3)ma_min(pGainer->config.smoothTimeInFrames,frameCount);
}
#if 0
if (pGainer->t>=pGainer->config.smoothTimeInFrames) {
ma_copy_and_apply_volume_factor_per_channel_f32(pFramesOutF32,pFramesInF32,frameCount,pGainer->config.Mh,pGainer->pNewGains);
ma_apply_volume_factor_f32(pFramesOutF32,frameCount*pGainer->config.Mh,pGainer->masterVolume);
if (pGainer->t==(M3)-1) {
pGainer->t=pGainer->config.smoothTimeInFrames;
}
} else {
if (pFramesOut !=NULL&&pFramesIn !=NULL) {
float a=(float)pGainer->t / pGainer->config.smoothTimeInFrames;
float d=1.0f / pGainer->config.smoothTimeInFrames;
M3 channelCount=pGainer->config.Mh;
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)*pGainer->masterVolume;
}
pFramesOutF32+=channelCount;
pFramesInF32+=channelCount;
a+=d;
if (a>1) {
 a=1;
}
}
}
pGainer->t=(M3)ma_min(pGainer->t+frameCount,pGainer->config.smoothTimeInFrames);
#if 0
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
if (pFramesOut !=NULL&&pFramesIn !=NULL) {
for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
 pFramesOutF32[iFrame*pGainer->config.Mh+iChannel]=pFramesInF32[iFrame*pGainer->config.Mh+iChannel]*ma_gainer_calculate_current_gain(pGainer,iChannel)*pGainer->masterVolume;
}
}
pGainer->t=ma_min(pGainer->t+1,pGainer->config.smoothTimeInFrames);
}
#endif
}
#endif
Mr Ms;
}
MA_API Me ma_gainer_process_pcm_frames(ma_gainer*pGainer,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pGainer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_gainer_process_pcm_frames_internal(pGainer,pFramesOut,pFramesIn,frameCount);
}
static Mv ma_gainer_set_gain_by_index(ma_gainer*pGainer,float newGain,M3 iChannel)
{
pGainer->pOldGains[iChannel]=ma_gainer_calculate_current_gain(pGainer,iChannel);
pGainer->pNewGains[iChannel]=newGain;
}
static Mv ma_gainer_reset_smoothing_time(ma_gainer*pGainer)
{
if (pGainer->t==(M3)-1) {
pGainer->t=pGainer->config.smoothTimeInFrames;
} else {
pGainer->t=0;
}
}
MA_API Me ma_gainer_set_gain(ma_gainer*pGainer,float newGain)
{
M3 iChannel;
if (pGainer==NULL) {
Mr MA_INVALID_ARGS;
}
for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
ma_gainer_set_gain_by_index(pGainer,newGain,iChannel);
}
ma_gainer_reset_smoothing_time(pGainer);
Mr Ms;
}
MA_API Me ma_gainer_set_gains(ma_gainer*pGainer,float*pNewGains)
{
M3 iChannel;
if (pGainer==NULL||pNewGains==NULL) {
Mr MA_INVALID_ARGS;
}
for (iChannel=0; iChannel<pGainer->config.Mh; iChannel+=1) {
ma_gainer_set_gain_by_index(pGainer,pNewGains[iChannel],iChannel);
}
ma_gainer_reset_smoothing_time(pGainer);
Mr Ms;
}
MA_API Me ma_gainer_set_master_volume(ma_gainer*pGainer,float volume)
{
if (pGainer==NULL) {
Mr MA_INVALID_ARGS;
}
pGainer->masterVolume=volume;
Mr Ms;
}
MA_API Me ma_gainer_get_master_volume(const ma_gainer*pGainer,float*pVolume)
{
if (pGainer==NULL||pVolume==NULL) {
Mr MA_INVALID_ARGS;
}
*pVolume=pGainer->masterVolume;
Mr Ms;
}
MA_API ma_panner_config ma_panner_config_init(ma_format format,M3 Mh)
{
ma_panner_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.mode=ma_pan_mode_balance;
config.pan=0;
Mr config;
}
MA_API Me ma_panner_init(const ma_panner_config*Mo,ma_panner*pPanner)
{
if (pPanner==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pPanner);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
pPanner->format=Mo->format;
pPanner->Mh=Mo->Mh;
pPanner->mode=Mo->mode;
pPanner->pan=Mo->pan;
Mr Ms;
}
static Mv ma_stereo_balance_pcm_frames_f32(float*pFramesOut,const float*pFramesIn,M6 frameCount,float pan)
{
M6 iFrame;
if (pan>0) {
float factor=1.0f-pan;
if (pFramesOut==pFramesIn) {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
pFramesOut[iFrame*2+0]=pFramesIn[iFrame*2+0]*factor;
}
} else {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
pFramesOut[iFrame*2+0]=pFramesIn[iFrame*2+0]*factor;
pFramesOut[iFrame*2+1]=pFramesIn[iFrame*2+1];
}
}
} else {
float factor=1.0f+pan;
if (pFramesOut==pFramesIn) {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
pFramesOut[iFrame*2+1]=pFramesIn[iFrame*2+1]*factor;
}
} else {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
pFramesOut[iFrame*2+0]=pFramesIn[iFrame*2+0];
pFramesOut[iFrame*2+1]=pFramesIn[iFrame*2+1]*factor;
}
}
}
}
static Mv ma_stereo_balance_pcm_frames(Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount,ma_format format,float pan)
{
if (pan==0) {
if (pFramesOut==pFramesIn) {
} else {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,format,2);
}
Mr;
}
switch (format) {
case ma_format_f32:ma_stereo_balance_pcm_frames_f32((float*)pFramesOut,(float*)pFramesIn,frameCount,pan); break;
default:
{
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,format,2);
} break;
}
}
static Mv ma_stereo_pan_pcm_frames_f32(float*pFramesOut,const float*pFramesIn,M6 frameCount,float pan)
{
M6 iFrame;
if (pan>0) {
float factorL0=1.0f-pan;
float factorL1=0.0f+pan;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
float sample0=(pFramesIn[iFrame*2+0]*factorL0);
float sample1=(pFramesIn[iFrame*2+0]*factorL1)+pFramesIn[iFrame*2+1];
pFramesOut[iFrame*2+0]=sample0;
pFramesOut[iFrame*2+1]=sample1;
}
} else {
float factorR0=0.0f-pan;
float factorR1=1.0f+pan;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
float sample0=pFramesIn[iFrame*2+0]+(pFramesIn[iFrame*2+1]*factorR0);
float sample1=(pFramesIn[iFrame*2+1]*factorR1);
pFramesOut[iFrame*2+0]=sample0;
pFramesOut[iFrame*2+1]=sample1;
}
}
}
static Mv ma_stereo_pan_pcm_frames(Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount,ma_format format,float pan)
{
if (pan==0) {
if (pFramesOut==pFramesIn) {
} else {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,format,2);
}
Mr;
}
switch (format) {
case ma_format_f32:ma_stereo_pan_pcm_frames_f32((float*)pFramesOut,(float*)pFramesIn,frameCount,pan); break;
default:
{
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,format,2);
} break;
}
}
MA_API Me ma_panner_process_pcm_frames(ma_panner*pPanner,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pPanner==NULL||pFramesOut==NULL||pFramesIn==NULL) {
Mr MA_INVALID_ARGS;
}
if (pPanner->Mh==2) {
if (pPanner->mode==ma_pan_mode_balance) {
ma_stereo_balance_pcm_frames(pFramesOut,pFramesIn,frameCount,pPanner->format,pPanner->pan);
} else {
ma_stereo_pan_pcm_frames(pFramesOut,pFramesIn,frameCount,pPanner->format,pPanner->pan);
}
} else {
if (pPanner->Mh==1) {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,pPanner->format,pPanner->Mh);
} else {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,pPanner->format,pPanner->Mh);
}
}
Mr Ms;
}
MA_API Mv ma_panner_set_mode(ma_panner*pPanner,ma_pan_mode mode)
{
if (pPanner==NULL) {
Mr;
}
pPanner->mode=mode;
}
MA_API ma_pan_mode ma_panner_get_mode(const ma_panner*pPanner)
{
if (pPanner==NULL) {
Mr ma_pan_mode_balance;
}
Mr pPanner->mode;
}
MA_API Mv ma_panner_set_pan(ma_panner*pPanner,float pan)
{
if (pPanner==NULL) {
Mr;
}
pPanner->pan=ma_clamp(pan,-1.0f,1.0f);
}
MA_API float ma_panner_get_pan(const ma_panner*pPanner)
{
if (pPanner==NULL) {
Mr 0;
}
Mr pPanner->pan;
}
MA_API ma_fader_config ma_fader_config_init(ma_format format,M3 Mh,M3 sampleRate)
{
ma_fader_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=sampleRate;
Mr config;
}
MA_API Me ma_fader_init(const ma_fader_config*Mo,ma_fader*pFader)
{
if (pFader==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFader);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32) {
Mr MA_INVALID_ARGS;
}
pFader->config=*Mo;
pFader->volumeBeg=1;
pFader->volumeEnd=1;
pFader->lengthInFrames=0;
pFader->cursorInFrames=0;
Mr Ms;
}
MA_API Me ma_fader_process_pcm_frames(ma_fader*pFader,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pFader==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFader->cursorInFrames<0) {
M6 absCursorInFrames=(M6)0-pFader->cursorInFrames;
if (absCursorInFrames>frameCount) {
absCursorInFrames=frameCount;
}
ma_copy_pcm_frames(pFramesOut,pFramesIn,absCursorInFrames,pFader->config.format,pFader->config.Mh);
pFader->cursorInFrames+=absCursorInFrames;
frameCount-=absCursorInFrames;
pFramesOut=ma_offset_ptr(pFramesOut,ma_get_bytes_per_frame(pFader->config.format,pFader->config.Mh)*absCursorInFrames);
pFramesIn=ma_offset_ptr(pFramesIn,ma_get_bytes_per_frame(pFader->config.format,pFader->config.Mh)*absCursorInFrames);
}
if (pFader->cursorInFrames>=0) {
if (frameCount+pFader->cursorInFrames>UINT_MAX) {
frameCount=UINT_MAX-pFader->cursorInFrames;
}
if (pFader->volumeBeg==pFader->volumeEnd) {
if (pFader->volumeBeg==1) {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,pFader->config.format,pFader->config.Mh);
} else {
ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut,pFramesIn,frameCount,pFader->config.format,pFader->config.Mh,pFader->volumeBeg);
}
} else {
if ((M6)pFader->cursorInFrames>=pFader->lengthInFrames) {
ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut,pFramesIn,frameCount,pFader->config.format,pFader->config.Mh,pFader->volumeEnd);
} else {
M6 iFrame;
M3 iChannel;
if (pFader->config.format==ma_format_f32) {
 const float*pFramesInF32=(const float*)pFramesIn; float*pFramesOutF32=( float*)pFramesOut;
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 float a=(M3)ma_min(pFader->cursorInFrames+iFrame,pFader->lengthInFrames) / (float)((M3)pFader->lengthInFrames);
 float volume=ma_mix_f32_fast(pFader->volumeBeg,pFader->volumeEnd,a);
 for (iChannel=0; iChannel<pFader->config.Mh; iChannel+=1) {
 pFramesOutF32[iFrame*pFader->config.Mh+iChannel]=pFramesInF32[iFrame*pFader->config.Mh+iChannel]*volume;
 }
 }
} else {
 Mr MA_NOT_IMPLEMENTED;
}
}
}
}
pFader->cursorInFrames+=frameCount;
Mr Ms;
}
MA_API Mv ma_fader_get_data_format(const ma_fader*pFader,ma_format*pFormat,M3*pChannels,M3*pSampleRate)
{
if (pFader==NULL) {
Mr;
}
if (pFormat !=NULL) {
*pFormat=pFader->config.format;
}
if (pChannels !=NULL) {
*pChannels=pFader->config.Mh;
}
if (pSampleRate !=NULL) {
*pSampleRate=pFader->config.sampleRate;
}
}
MA_API Mv ma_fader_set_fade(ma_fader*pFader,float volumeBeg,float volumeEnd,M6 lengthInFrames)
{
ma_fader_set_fade_ex(pFader,volumeBeg,volumeEnd,lengthInFrames,0);
}
MA_API Mv ma_fader_set_fade_ex(ma_fader*pFader,float volumeBeg,float volumeEnd,M6 lengthInFrames,ma_int64 startOffsetInFrames)
{
if (pFader==NULL) {
Mr;
}
if (volumeBeg<0) {
volumeBeg=ma_fader_get_current_volume(pFader);
}
if (lengthInFrames>UINT_MAX) {
lengthInFrames=UINT_MAX;
}
if (startOffsetInFrames>INT_MAX) {
startOffsetInFrames=INT_MAX;
}
pFader->volumeBeg=volumeBeg;
pFader->volumeEnd=volumeEnd;
pFader->lengthInFrames=lengthInFrames;
pFader->cursorInFrames=-startOffsetInFrames;
}
MA_API float ma_fader_get_current_volume(const ma_fader*pFader)
{
if (pFader==NULL) {
Mr 0.0f;
}
if (pFader->cursorInFrames<0) {
Mr 1.0f;
}
if (pFader->cursorInFrames==0) {
Mr pFader->volumeBeg;
} else if ((M6)pFader->cursorInFrames>=pFader->lengthInFrames) {
Mr pFader->volumeEnd;
} else {
Mr ma_mix_f32_fast(pFader->volumeBeg,pFader->volumeEnd,(M3)pFader->cursorInFrames / (float)((M3)pFader->lengthInFrames));
}
}
MA_API ma_vec3f ma_vec3f_init_3f(float x,float y,float z)
{
ma_vec3f v;
v.x=x;
v.y=y;
v.z=z;
Mr v;
}
MA_API ma_vec3f ma_vec3f_sub(ma_vec3f a,ma_vec3f b)
{
Mr ma_vec3f_init_3f(
a.x-b.x,a.y-b.y,a.z-b.z
);
}
MA_API ma_vec3f ma_vec3f_neg(ma_vec3f a)
{
Mr ma_vec3f_init_3f(
-a.x,-a.y,-a.z
);
}
MA_API float ma_vec3f_dot(ma_vec3f a,ma_vec3f b)
{
Mr a.x*b.x+a.y*b.y+a.z*b.z;
}
MA_API float ma_vec3f_len2(ma_vec3f v)
{
Mr ma_vec3f_dot(v,v);
}
MA_API float ma_vec3f_len(ma_vec3f v)
{
Mr (float)ma_sqrtd(ma_vec3f_len2(v));
}
MA_API float ma_vec3f_dist(ma_vec3f a,ma_vec3f b)
{
Mr ma_vec3f_len(ma_vec3f_sub(a,b));
}
MA_API ma_vec3f ma_vec3f_normalize(ma_vec3f v)
{
float invLen;
float len2=ma_vec3f_len2(v);
if (len2==0) {
Mr ma_vec3f_init_3f(0,0,0);
}
invLen=ma_rsqrtf(len2);
v.x*=invLen;
v.y*=invLen;
v.z*=invLen;
Mr v;
}
MA_API ma_vec3f ma_vec3f_cross(ma_vec3f a,ma_vec3f b)
{
Mr ma_vec3f_init_3f(
a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x
);
}
MA_API Mv ma_atomic_vec3f_init(ma_atomic_vec3f*v,ma_vec3f value)
{
v->v=value;
v->lock=0;
}
MA_API Mv ma_atomic_vec3f_set(ma_atomic_vec3f*v,ma_vec3f value)
{
ma_spinlock_lock(&v->lock);
{
v->v=value;
}
ma_spinlock_unlock(&v->lock);
}
MA_API ma_vec3f ma_atomic_vec3f_get(ma_atomic_vec3f*v)
{
ma_vec3f r;
ma_spinlock_lock(&v->lock);
{
r=v->v;
}
ma_spinlock_unlock(&v->lock);
Mr r;
}
static Mv ma_channel_map_apply_f32(float*pFramesOut,const ma_channel*pChannelMapOut,M3 channelsOut,const float*pFramesIn,const ma_channel*pChannelMapIn,M3 channelsIn,M6 frameCount,ma_channel_mix_mode mode,ma_mono_expansion_mode monoExpansionMode);
static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition);
#ifndef MA_DEFAULT_SPEED_OF_SOUND
#define MA_DEFAULT_SPEED_OF_SOUND 343.3f
#endif
static ma_vec3f g_maChannelDirections[MA_CHANNEL_POSITION_COUNT]={
{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{-0.7071f,0.0f,-0.7071f },{+0.7071f,0.0f,-0.7071f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{-0.7071f,0.0f,+0.7071f },{+0.7071f,0.0f,+0.7071f },{-0.3162f,0.0f,-0.9487f },{+0.3162f,0.0f,-0.9487f },{ 0.0f,0.0f,+1.0f },{-1.0f,0.0f,0.0f },{+1.0f,0.0f,0.0f },{ 0.0f,+1.0f,0.0f },{-0.5774f,+0.5774f,-0.5774f },{ 0.0f,+0.7071f,-0.7071f },{+0.5774f,+0.5774f,-0.5774f },{-0.5774f,+0.5774f,+0.5774f },{ 0.0f,+0.7071f,+0.7071f },{+0.5774f,+0.5774f,+0.5774f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f },{ 0.0f,0.0f,-1.0f }
};
static ma_vec3f ma_get_channel_direction(ma_channel channel)
{
if (channel>=MA_CHANNEL_POSITION_COUNT) {
Mr ma_vec3f_init_3f(0,0,-1);
} else {
Mr g_maChannelDirections[channel];
}
}
static float ma_attenuation_inverse(float distance,float minDistance,float maxDistance,float rolloff)
{
if (minDistance>=maxDistance) {
Mr 1;
}
Mr minDistance / (minDistance+rolloff*(ma_clamp(distance,minDistance,maxDistance)-minDistance));
}
static float ma_attenuation_linear(float distance,float minDistance,float maxDistance,float rolloff)
{
if (minDistance>=maxDistance) {
Mr 1;
}
Mr 1-rolloff*(ma_clamp(distance,minDistance,maxDistance)-minDistance) / (maxDistance-minDistance);
}
static float ma_attenuation_exponential(float distance,float minDistance,float maxDistance,float rolloff)
{
if (minDistance>=maxDistance) {
Mr 1;
}
Mr (float)ma_powd(ma_clamp(distance,minDistance,maxDistance) / minDistance,-rolloff);
}
static float ma_doppler_pitch(ma_vec3f relativePosition,ma_vec3f sourceVelocity,ma_vec3f listenVelocity,float speedOfSound,float dopplerFactor)
{
float len;
float vls;
float vss;
len=ma_vec3f_len(relativePosition);
if (len==0) {
Mr 1.0;
}
vls=ma_vec3f_dot(relativePosition,listenVelocity) / len;
vss=ma_vec3f_dot(relativePosition,sourceVelocity) / len;
vls=ma_min(vls,speedOfSound / dopplerFactor);
vss=ma_min(vss,speedOfSound / dopplerFactor);
Mr (speedOfSound-dopplerFactor*vls) / (speedOfSound-dopplerFactor*vss);
}
static Mv ma_get_default_channel_map_for_spatializer(ma_channel*pChannelMap,size_t channelMapCap,M3 channelCount)
{
if (channelCount==2) {
pChannelMap[0]=MA_CHANNEL_SIDE_LEFT;
pChannelMap[1]=MA_CHANNEL_SIDE_RIGHT;
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,channelCount);
}
}
MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(M3 channelsOut)
{
ma_spatializer_listener_config config;
MA_ZERO_OBJECT(&config);
config.channelsOut=channelsOut;
config.pChannelMapOut=NULL;
config.handedness=ma_handedness_right;
config.worldUp=ma_vec3f_init_3f(0,1,0);
config.coneInnerAngleInRadians=6.283185f;
config.coneOuterAngleInRadians=6.283185f;
config.coneOuterGain=0;
config.speedOfSound=343.3f;
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t channelMapOutOffset;
} ma_spatializer_listener_heap_layout;
static Me ma_spatializer_listener_get_heap_layout(const ma_spatializer_listener_config*Mo,ma_spatializer_listener_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->channelsOut==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->channelMapOutOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(sizeof(*Mo->pChannelMapOut)*Mo->channelsOut);
Mr Ms;
}
MA_API Me ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_spatializer_listener_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_spatializer_listener_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config*Mo,Mv*pHeap,ma_spatializer_listener*pListener)
{
Me Mf;
ma_spatializer_listener_heap_layout heapLayout;
if (pListener==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pListener);
Mf=ma_spatializer_listener_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pListener->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pListener->config=*Mo;
ma_atomic_vec3f_init(&pListener->position,ma_vec3f_init_3f(0,0,0));
ma_atomic_vec3f_init(&pListener->direction,ma_vec3f_init_3f(0,0,-1));
ma_atomic_vec3f_init(&pListener->velocity,ma_vec3f_init_3f(0,0,0));
pListener->isEnabled=MA_TRUE;
if (pListener->config.handedness==ma_handedness_left) {
ma_vec3f negDir=ma_vec3f_neg(ma_spatializer_listener_get_direction(pListener));
ma_spatializer_listener_set_direction(pListener,negDir.x,negDir.y,negDir.z);
}
pListener->config.pChannelMapOut=(ma_channel*)ma_offset_ptr(pHeap,heapLayout.channelMapOutOffset);
if (Mo->pChannelMapOut==NULL) {
ma_get_default_channel_map_for_spatializer(pListener->config.pChannelMapOut,Mo->channelsOut,Mo->channelsOut);
} else {
ma_channel_map_copy_or_default(pListener->config.pChannelMapOut,Mo->channelsOut,Mo->pChannelMapOut,Mo->channelsOut);
}
Mr Ms;
}
MA_API Me ma_spatializer_listener_init(const ma_spatializer_listener_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_spatializer_listener*pListener)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_spatializer_listener_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_spatializer_listener_init_preallocated(Mo,pHeap,pListener);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pListener->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_spatializer_listener_uninit(ma_spatializer_listener*pListener,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pListener==NULL) {
Mr;
}
if (pListener->_ownsHeap) {
ma_free(pListener->_pHeap,pAllocationCallbacks);
}
}
MA_API ma_channel*ma_spatializer_listener_get_channel_map(ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr NULL;
}
Mr pListener->config.pChannelMapOut;
}
MA_API Mv ma_spatializer_listener_set_cone(ma_spatializer_listener*pListener,float innerAngleInRadians,float outerAngleInRadians,float outerGain)
{
if (pListener==NULL) {
Mr;
}
pListener->config.coneInnerAngleInRadians=innerAngleInRadians;
pListener->config.coneOuterAngleInRadians=outerAngleInRadians;
pListener->config.coneOuterGain=outerGain;
}
MA_API Mv ma_spatializer_listener_get_cone(const ma_spatializer_listener*pListener,float*pInnerAngleInRadians,float*pOuterAngleInRadians,float*pOuterGain)
{
if (pListener==NULL) {
Mr;
}
if (pInnerAngleInRadians !=NULL) {
*pInnerAngleInRadians=pListener->config.coneInnerAngleInRadians;
}
if (pOuterAngleInRadians !=NULL) {
*pOuterAngleInRadians=pListener->config.coneOuterAngleInRadians;
}
if (pOuterGain !=NULL) {
*pOuterGain=pListener->config.coneOuterGain;
}
}
MA_API Mv ma_spatializer_listener_set_position(ma_spatializer_listener*pListener,float x,float y,float z)
{
if (pListener==NULL) {
Mr;
}
ma_atomic_vec3f_set(&pListener->position,ma_vec3f_init_3f(x,y,z));
}
MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr ma_vec3f_init_3f(0,0,0);
}
Mr ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->position);
}
MA_API Mv ma_spatializer_listener_set_direction(ma_spatializer_listener*pListener,float x,float y,float z)
{
if (pListener==NULL) {
Mr;
}
ma_atomic_vec3f_set(&pListener->direction,ma_vec3f_init_3f(x,y,z));
}
MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr ma_vec3f_init_3f(0,0,-1);
}
Mr ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->direction);
}
MA_API Mv ma_spatializer_listener_set_velocity(ma_spatializer_listener*pListener,float x,float y,float z)
{
if (pListener==NULL) {
Mr;
}
ma_atomic_vec3f_set(&pListener->velocity,ma_vec3f_init_3f(x,y,z));
}
MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr ma_vec3f_init_3f(0,0,0);
}
Mr ma_atomic_vec3f_get((ma_atomic_vec3f*)&pListener->velocity);
}
MA_API Mv ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener*pListener,float speedOfSound)
{
if (pListener==NULL) {
Mr;
}
pListener->config.speedOfSound=speedOfSound;
}
MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr 0;
}
Mr pListener->config.speedOfSound;
}
MA_API Mv ma_spatializer_listener_set_world_up(ma_spatializer_listener*pListener,float x,float y,float z)
{
if (pListener==NULL) {
Mr;
}
pListener->config.worldUp=ma_vec3f_init_3f(x,y,z);
}
MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr ma_vec3f_init_3f(0,1,0);
}
Mr pListener->config.worldUp;
}
MA_API Mv ma_spatializer_listener_set_enabled(ma_spatializer_listener*pListener,ma_bool32 isEnabled)
{
if (pListener==NULL) {
Mr;
}
pListener->isEnabled=isEnabled;
}
MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener*pListener)
{
if (pListener==NULL) {
Mr MA_FALSE;
}
Mr pListener->isEnabled;
}
MA_API ma_spatializer_config ma_spatializer_config_init(M3 channelsIn,M3 channelsOut)
{
ma_spatializer_config config;
MA_ZERO_OBJECT(&config);
config.channelsIn=channelsIn;
config.channelsOut=channelsOut;
config.pChannelMapIn=NULL;
config.attenuationModel=ma_attenuation_model_inverse;
config.positioning=ma_positioning_absolute;
config.handedness=ma_handedness_right;
config.minGain=0;
config.maxGain=1;
config.minDistance=1;
config.maxDistance=MA_FLT_MAX;
config.rolloff=1;
config.coneInnerAngleInRadians=6.283185f;
config.coneOuterAngleInRadians=6.283185f;
config.coneOuterGain=0.0f;
config.dopplerFactor=1;
config.directionalAttenuationFactor=1;
config.minSpatializationChannelGain=0.2f;
config.gainSmoothTimeInFrames=360;
Mr config;
}
static ma_gainer_config ma_spatializer_gainer_config_init(const ma_spatializer_config*Mo)
{
MA_ASSERT(Mo !=NULL);
Mr ma_gainer_config_init(Mo->channelsOut,Mo->gainSmoothTimeInFrames);
}
static Me ma_spatializer_validate_config(const ma_spatializer_config*Mo)
{
MA_ASSERT(Mo !=NULL);
if (Mo->channelsIn==0||Mo->channelsOut==0) {
Mr MA_INVALID_ARGS;
}
Mr Ms;
}
typedef struct
{
size_t sizeInBytes;
size_t channelMapInOffset;
size_t newChannelGainsOffset;
size_t gainerOffset;
} ma_spatializer_heap_layout;
static Me ma_spatializer_get_heap_layout(const ma_spatializer_config*Mo,ma_spatializer_heap_layout*pHeapLayout)
{
Me Mf;
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_spatializer_validate_config(Mo);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->channelMapInOffset=MA_SIZE_MAX;
if (Mo->pChannelMapIn !=NULL) {
pHeapLayout->channelMapInOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(sizeof(*Mo->pChannelMapIn)*Mo->channelsIn);
}
pHeapLayout->newChannelGainsOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(sizeof(float)*Mo->channelsOut);
{
size_t gainerHeapSizeInBytes;
ma_gainer_config gainerConfig;
gainerConfig=ma_spatializer_gainer_config_init(Mo);
Mf=ma_gainer_get_heap_size(&gainerConfig,&gainerHeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->gainerOffset=pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes+=ma_align_64(gainerHeapSizeInBytes);
}
Mr Ms;
}
MA_API Me ma_spatializer_get_heap_size(const ma_spatializer_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_spatializer_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_spatializer_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_spatializer_init_preallocated(const ma_spatializer_config*Mo,Mv*pHeap,ma_spatializer*pSpatializer)
{
Me Mf;
ma_spatializer_heap_layout heapLayout;
ma_gainer_config gainerConfig;
if (pSpatializer==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pSpatializer);
if (Mo==NULL||pHeap==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_spatializer_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pSpatializer->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pSpatializer->channelsIn=Mo->channelsIn;
pSpatializer->channelsOut=Mo->channelsOut;
pSpatializer->attenuationModel=Mo->attenuationModel;
pSpatializer->positioning=Mo->positioning;
pSpatializer->handedness=Mo->handedness;
pSpatializer->minGain=Mo->minGain;
pSpatializer->maxGain=Mo->maxGain;
pSpatializer->minDistance=Mo->minDistance;
pSpatializer->maxDistance=Mo->maxDistance;
pSpatializer->rolloff=Mo->rolloff;
pSpatializer->coneInnerAngleInRadians=Mo->coneInnerAngleInRadians;
pSpatializer->coneOuterAngleInRadians=Mo->coneOuterAngleInRadians;
pSpatializer->coneOuterGain=Mo->coneOuterGain;
pSpatializer->dopplerFactor=Mo->dopplerFactor;
pSpatializer->minSpatializationChannelGain=Mo->minSpatializationChannelGain;
pSpatializer->directionalAttenuationFactor=Mo->directionalAttenuationFactor;
pSpatializer->gainSmoothTimeInFrames=Mo->gainSmoothTimeInFrames;
ma_atomic_vec3f_init(&pSpatializer->position,ma_vec3f_init_3f(0,0,0));
ma_atomic_vec3f_init(&pSpatializer->direction,ma_vec3f_init_3f(0,0,-1));
ma_atomic_vec3f_init(&pSpatializer->velocity,ma_vec3f_init_3f(0,0,0));
pSpatializer->dopplerPitch=1;
if (pSpatializer->handedness==ma_handedness_left) {
ma_vec3f negDir=ma_vec3f_neg(ma_spatializer_get_direction(pSpatializer));
ma_spatializer_set_direction(pSpatializer,negDir.x,negDir.y,negDir.z);
}
if (Mo->pChannelMapIn !=NULL) {
pSpatializer->pChannelMapIn=(ma_channel*)ma_offset_ptr(pHeap,heapLayout.channelMapInOffset);
ma_channel_map_copy_or_default(pSpatializer->pChannelMapIn,pSpatializer->channelsIn,Mo->pChannelMapIn,pSpatializer->channelsIn);
}
pSpatializer->pNewChannelGainsOut=(float*)ma_offset_ptr(pHeap,heapLayout.newChannelGainsOffset);
gainerConfig=ma_spatializer_gainer_config_init(Mo);
Mf=ma_gainer_init_preallocated(&gainerConfig,ma_offset_ptr(pHeap,heapLayout.gainerOffset),&pSpatializer->gainer);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_spatializer_init(const ma_spatializer_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_spatializer*pSpatializer)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_spatializer_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_spatializer_init_preallocated(Mo,pHeap,pSpatializer);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pSpatializer->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_spatializer_uninit(ma_spatializer*pSpatializer,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pSpatializer==NULL) {
Mr;
}
ma_gainer_uninit(&pSpatializer->gainer,pAllocationCallbacks);
if (pSpatializer->_ownsHeap) {
ma_free(pSpatializer->_pHeap,pAllocationCallbacks);
}
}
static float ma_calculate_angular_gain(ma_vec3f dirA,ma_vec3f dirB,float coneInnerAngleInRadians,float coneOuterAngleInRadians,float coneOuterGain)
{
if (coneInnerAngleInRadians<6.283185f) {
float angularGain=1;
float cutoffInner=(float)ma_cosd(coneInnerAngleInRadians*0.5f);
float cutoffOuter=(float)ma_cosd(coneOuterAngleInRadians*0.5f);
float d;
d=ma_vec3f_dot(dirA,dirB);
if (d>cutoffInner) {
angularGain=1;
} else {
if (d>cutoffOuter) {
angularGain=ma_mix_f32(coneOuterGain,1,(d-cutoffOuter) / (cutoffInner-cutoffOuter));
} else {
angularGain=coneOuterGain;
}
}
Mr angularGain;
} else {
Mr 1;
}
}
MA_API Me ma_spatializer_process_pcm_frames(ma_spatializer*pSpatializer,ma_spatializer_listener*pListener,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
ma_channel*pChannelMapIn=pSpatializer->pChannelMapIn;
ma_channel*pChannelMapOut=pListener->config.pChannelMapOut;
if (pSpatializer==NULL) {
Mr MA_INVALID_ARGS;
}
if (ma_atomic_load_i32(&pSpatializer->attenuationModel)==ma_attenuation_model_none) {
if (ma_spatializer_listener_is_enabled(pListener)) {
if (pSpatializer->channelsIn==pSpatializer->channelsOut) {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,ma_format_f32,pSpatializer->channelsIn);
} else {
ma_channel_map_apply_f32((float*)pFramesOut,pChannelMapOut,pSpatializer->channelsOut,(const float*)pFramesIn,pChannelMapIn,pSpatializer->channelsIn,frameCount,ma_channel_mix_mode_rectangular,ma_mono_expansion_mode_default);
}
} else {
ma_silence_pcm_frames(pFramesOut,frameCount,ma_format_f32,pSpatializer->channelsOut);
}
pSpatializer->dopplerPitch=1;
} else {
ma_vec3f relativePosNormalized;
ma_vec3f relativePos;
ma_vec3f relativeDir;
ma_vec3f listenerVel;
float speedOfSound;
float distance=0;
float gain=1;
M3 iChannel;
const M3 channelsOut=pSpatializer->channelsOut;
const M3 channelsIn=pSpatializer->channelsIn;
float minDistance=ma_spatializer_get_min_distance(pSpatializer);
float maxDistance=ma_spatializer_get_max_distance(pSpatializer);
float rolloff=ma_spatializer_get_rolloff(pSpatializer);
float dopplerFactor=ma_spatializer_get_doppler_factor(pSpatializer);
if (pListener !=NULL) {
listenerVel=ma_spatializer_listener_get_velocity(pListener);
speedOfSound=pListener->config.speedOfSound;
} else {
listenerVel=ma_vec3f_init_3f(0,0,0);
speedOfSound=MA_DEFAULT_SPEED_OF_SOUND;
}
if (pListener==NULL||ma_spatializer_get_positioning(pSpatializer)==ma_positioning_relative) {
relativePos=ma_spatializer_get_position(pSpatializer);
relativeDir=ma_spatializer_get_direction(pSpatializer);
} else {
ma_spatializer_get_relative_position_and_direction(pSpatializer,pListener,&relativePos,&relativeDir);
}
distance=ma_vec3f_len(relativePos);
switch (ma_spatializer_get_attenuation_model(pSpatializer)) {
case ma_attenuation_model_inverse:
{
gain=ma_attenuation_inverse(distance,minDistance,maxDistance,rolloff);
} break;
case ma_attenuation_model_linear:
{
gain=ma_attenuation_linear(distance,minDistance,maxDistance,rolloff);
} break;
case ma_attenuation_model_exponential:
{
gain=ma_attenuation_exponential(distance,minDistance,maxDistance,rolloff);
} break;
case ma_attenuation_model_none:
default:
{
gain=1;
} break;
}
if (distance>0.001f) {
float distanceInv=1/distance;
relativePosNormalized=relativePos;
relativePosNormalized.x*=distanceInv;
relativePosNormalized.y*=distanceInv;
relativePosNormalized.z*=distanceInv;
} else {
distance=0;
relativePosNormalized=ma_vec3f_init_3f(0,0,0);
}
if (distance>0) {
float spatializerConeInnerAngle;
float spatializerConeOuterAngle;
float spatializerConeOuterGain;
ma_spatializer_get_cone(pSpatializer,&spatializerConeInnerAngle,&spatializerConeOuterAngle,&spatializerConeOuterGain);
gain*=ma_calculate_angular_gain(relativeDir,ma_vec3f_neg(relativePosNormalized),spatializerConeInnerAngle,spatializerConeOuterAngle,spatializerConeOuterGain);
if (pListener !=NULL&&pListener->config.coneInnerAngleInRadians<6.283185f) {
ma_vec3f listenerDirection;
float listenerInnerAngle;
float listenerOuterAngle;
float listenerOuterGain;
if (pListener->config.handedness==ma_handedness_right) {
 listenerDirection=ma_vec3f_init_3f(0,0,-1);
} else {
 listenerDirection=ma_vec3f_init_3f(0,0,+1);
}
listenerInnerAngle=pListener->config.coneInnerAngleInRadians;
listenerOuterAngle=pListener->config.coneOuterAngleInRadians;
listenerOuterGain=pListener->config.coneOuterGain;
gain*=ma_calculate_angular_gain(listenerDirection,relativePosNormalized,listenerInnerAngle,listenerOuterAngle,listenerOuterGain);
}
} else {
}
gain=ma_clamp(gain,ma_spatializer_get_min_gain(pSpatializer),ma_spatializer_get_max_gain(pSpatializer));
for (iChannel=0; iChannel<channelsOut; iChannel+=1) {
pSpatializer->pNewChannelGainsOut[iChannel]=gain;
}
if (ma_spatializer_listener_is_enabled(pListener)) {
ma_channel_map_apply_f32((float*)pFramesOut,pChannelMapOut,channelsOut,(const float*)pFramesIn,pChannelMapIn,channelsIn,frameCount,ma_channel_mix_mode_rectangular,ma_mono_expansion_mode_default);
} else {
ma_silence_pcm_frames(pFramesOut,frameCount,ma_format_f32,pSpatializer->channelsOut);
}
MA_ASSERT(pChannelMapOut !=NULL);
if (distance>0) {
ma_vec3f unitPos=relativePos;
float distanceInv=1/distance;
unitPos.x*=distanceInv;
unitPos.y*=distanceInv;
unitPos.z*=distanceInv;
for (iChannel=0; iChannel<channelsOut; iChannel+=1) {
ma_channel channelOut;
float d;
float dMin;
channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannel);
if (ma_is_spatial_channel_position(channelOut)) {
 d=ma_mix_f32_fast(1,ma_vec3f_dot(unitPos,ma_get_channel_direction(channelOut)),ma_spatializer_get_directional_attenuation_factor(pSpatializer));
} else {
 d=1;
}
dMin=pSpatializer->minSpatializationChannelGain;
#if 1
{
 d=(d+1)*0.5f;
 d=ma_max(d,dMin);
 pSpatializer->pNewChannelGainsOut[iChannel]*=d;
}
#else
{
 if (d<0) {
 d+=1;
 d=ma_max(d,dMin);
 channelGainsOut[iChannel]*=d;
 }
}
#endif
}
} else {
}
ma_gainer_set_gains(&pSpatializer->gainer,pSpatializer->pNewChannelGainsOut);
ma_gainer_process_pcm_frames(&pSpatializer->gainer,pFramesOut,pFramesOut,frameCount);
if (dopplerFactor>0) {
pSpatializer->dopplerPitch=ma_doppler_pitch(ma_vec3f_sub(ma_spatializer_listener_get_position(pListener),ma_spatializer_get_position(pSpatializer)),ma_spatializer_get_velocity(pSpatializer),listenerVel,speedOfSound,dopplerFactor);
} else {
pSpatializer->dopplerPitch=1;
}
}
Mr Ms;
}
MA_API Me ma_spatializer_set_master_volume(ma_spatializer*pSpatializer,float volume)
{
if (pSpatializer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_gainer_set_master_volume(&pSpatializer->gainer,volume);
}
MA_API Me ma_spatializer_get_master_volume(const ma_spatializer*pSpatializer,float*pVolume)
{
if (pSpatializer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_gainer_get_master_volume(&pSpatializer->gainer,pVolume);
}
MA_API M3 ma_spatializer_get_input_channels(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr pSpatializer->channelsIn;
}
MA_API M3 ma_spatializer_get_output_channels(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr pSpatializer->channelsOut;
}
MA_API Mv ma_spatializer_set_attenuation_model(ma_spatializer*pSpatializer,ma_attenuation_model attenuationModel)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_i32(&pSpatializer->attenuationModel,attenuationModel);
}
MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr ma_attenuation_model_none;
}
Mr (ma_attenuation_model)ma_atomic_load_i32(&pSpatializer->attenuationModel);
}
MA_API Mv ma_spatializer_set_positioning(ma_spatializer*pSpatializer,ma_positioning positioning)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_i32(&pSpatializer->positioning,positioning);
}
MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr ma_positioning_absolute;
}
Mr (ma_positioning)ma_atomic_load_i32(&pSpatializer->positioning);
}
MA_API Mv ma_spatializer_set_rolloff(ma_spatializer*pSpatializer,float rolloff)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->rolloff,rolloff);
}
MA_API float ma_spatializer_get_rolloff(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr ma_atomic_load_f32(&pSpatializer->rolloff);
}
MA_API Mv ma_spatializer_set_min_gain(ma_spatializer*pSpatializer,float minGain)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->minGain,minGain);
}
MA_API float ma_spatializer_get_min_gain(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr ma_atomic_load_f32(&pSpatializer->minGain);
}
MA_API Mv ma_spatializer_set_max_gain(ma_spatializer*pSpatializer,float maxGain)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->maxGain,maxGain);
}
MA_API float ma_spatializer_get_max_gain(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr ma_atomic_load_f32(&pSpatializer->maxGain);
}
MA_API Mv ma_spatializer_set_min_distance(ma_spatializer*pSpatializer,float minDistance)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->minDistance,minDistance);
}
MA_API float ma_spatializer_get_min_distance(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr ma_atomic_load_f32(&pSpatializer->minDistance);
}
MA_API Mv ma_spatializer_set_max_distance(ma_spatializer*pSpatializer,float maxDistance)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->maxDistance,maxDistance);
}
MA_API float ma_spatializer_get_max_distance(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 0;
}
Mr ma_atomic_load_f32(&pSpatializer->maxDistance);
}
MA_API Mv ma_spatializer_set_cone(ma_spatializer*pSpatializer,float innerAngleInRadians,float outerAngleInRadians,float outerGain)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->coneInnerAngleInRadians,innerAngleInRadians);
ma_atomic_exchange_f32(&pSpatializer->coneOuterAngleInRadians,outerAngleInRadians);
ma_atomic_exchange_f32(&pSpatializer->coneOuterGain,outerGain);
}
MA_API Mv ma_spatializer_get_cone(const ma_spatializer*pSpatializer,float*pInnerAngleInRadians,float*pOuterAngleInRadians,float*pOuterGain)
{
if (pSpatializer==NULL) {
Mr;
}
if (pInnerAngleInRadians !=NULL) {
*pInnerAngleInRadians=ma_atomic_load_f32(&pSpatializer->coneInnerAngleInRadians);
}
if (pOuterAngleInRadians !=NULL) {
*pOuterAngleInRadians=ma_atomic_load_f32(&pSpatializer->coneOuterAngleInRadians);
}
if (pOuterGain !=NULL) {
*pOuterGain=ma_atomic_load_f32(&pSpatializer->coneOuterGain);
}
}
MA_API Mv ma_spatializer_set_doppler_factor(ma_spatializer*pSpatializer,float dopplerFactor)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->dopplerFactor,dopplerFactor);
}
MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 1;
}
Mr ma_atomic_load_f32(&pSpatializer->dopplerFactor);
}
MA_API Mv ma_spatializer_set_directional_attenuation_factor(ma_spatializer*pSpatializer,float directionalAttenuationFactor)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_exchange_f32(&pSpatializer->directionalAttenuationFactor,directionalAttenuationFactor);
}
MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr 1;
}
Mr ma_atomic_load_f32(&pSpatializer->directionalAttenuationFactor);
}
MA_API Mv ma_spatializer_set_position(ma_spatializer*pSpatializer,float x,float y,float z)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_vec3f_set(&pSpatializer->position,ma_vec3f_init_3f(x,y,z));
}
MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr ma_vec3f_init_3f(0,0,0);
}
Mr ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->position);
}
MA_API Mv ma_spatializer_set_direction(ma_spatializer*pSpatializer,float x,float y,float z)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_vec3f_set(&pSpatializer->direction,ma_vec3f_init_3f(x,y,z));
}
MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr ma_vec3f_init_3f(0,0,-1);
}
Mr ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->direction);
}
MA_API Mv ma_spatializer_set_velocity(ma_spatializer*pSpatializer,float x,float y,float z)
{
if (pSpatializer==NULL) {
Mr;
}
ma_atomic_vec3f_set(&pSpatializer->velocity,ma_vec3f_init_3f(x,y,z));
}
MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer*pSpatializer)
{
if (pSpatializer==NULL) {
Mr ma_vec3f_init_3f(0,0,0);
}
Mr ma_atomic_vec3f_get((ma_atomic_vec3f*)&pSpatializer->velocity);
}
MA_API Mv ma_spatializer_get_relative_position_and_direction(const ma_spatializer*pSpatializer,const ma_spatializer_listener*pListener,ma_vec3f*pRelativePos,ma_vec3f*pRelativeDir)
{
if (pRelativePos !=NULL) {
pRelativePos->x=0;
pRelativePos->y=0;
pRelativePos->z=0;
}
if (pRelativeDir !=NULL) {
pRelativeDir->x=0;
pRelativeDir->y=0;
pRelativeDir->z=-1;
}
if (pSpatializer==NULL) {
Mr;
}
if (pListener==NULL||ma_spatializer_get_positioning(pSpatializer)==ma_positioning_relative) {
if (pRelativePos !=NULL) {
*pRelativePos=ma_spatializer_get_position(pSpatializer);
}
if (pRelativeDir !=NULL) {
*pRelativeDir=ma_spatializer_get_direction(pSpatializer);
}
} else {
ma_vec3f spatializerPosition;
ma_vec3f spatializerDirection;
ma_vec3f listenerPosition;
ma_vec3f listenerDirection;
ma_vec3f v;
ma_vec3f axisX;
ma_vec3f axisY;
ma_vec3f axisZ;
float m[4][4];
spatializerPosition=ma_spatializer_get_position(pSpatializer);
spatializerDirection=ma_spatializer_get_direction(pSpatializer);
listenerPosition=ma_spatializer_listener_get_position(pListener);
listenerDirection=ma_spatializer_listener_get_direction(pListener);
axisZ=ma_vec3f_normalize(listenerDirection);
axisX=ma_vec3f_normalize(ma_vec3f_cross(axisZ,pListener->config.worldUp));
if (ma_vec3f_len2(axisX)==0) {
axisX=ma_vec3f_init_3f(1,0,0);
}
axisY=ma_vec3f_cross(axisX,axisZ);
if (pListener->config.handedness==ma_handedness_left) {
axisX=ma_vec3f_neg(axisX);
}
m[0][0]=axisX.x; m[1][0]=axisX.y; m[2][0]=axisX.z; m[3][0]=-ma_vec3f_dot(axisX,listenerPosition);
m[0][1]=axisY.x; m[1][1]=axisY.y; m[2][1]=axisY.z; m[3][1]=-ma_vec3f_dot(axisY,listenerPosition);
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),listenerPosition);
m[0][3]=0; m[1][3]=0; m[2][3]=0; m[3][3]=1;
if (pRelativePos !=NULL) {
v=spatializerPosition;
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;
}
if (pRelativeDir !=NULL) {
v=spatializerDirection;
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;
}
}
}
MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format,M3 Mh,M3 sampleRateIn,M3 sampleRateOut)
{
ma_linear_resampler_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRateIn=sampleRateIn;
config.sampleRateOut=sampleRateOut;
config.lpfOrder=ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER,MA_MAX_FILTER_ORDER);
config.lpfNyquistFactor=1;
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t x0Offset;
size_t x1Offset;
size_t lpfOffset;
} ma_linear_resampler_heap_layout;
static Mv ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler*pResampler,M3 oldSampleRateOut,M3 newSampleRateOut)
{
M3 oldRateTimeWhole=pResampler->inTimeFrac / oldSampleRateOut;
M3 oldRateTimeFract=pResampler->inTimeFrac % oldSampleRateOut;
pResampler->inTimeFrac=
(oldRateTimeWhole*newSampleRateOut)+
((oldRateTimeFract*newSampleRateOut) / oldSampleRateOut);
pResampler->inTimeInt+=pResampler->inTimeFrac / pResampler->config.sampleRateOut;
pResampler->inTimeFrac=pResampler->inTimeFrac % pResampler->config.sampleRateOut;
}
static Me ma_linear_resampler_set_rate_internal(ma_linear_resampler*pResampler,Mv*pHeap,ma_linear_resampler_heap_layout*pHeapLayout,M3 sampleRateIn,M3 sampleRateOut,ma_bool32 isResamplerAlreadyInitialized)
{
Me Mf;
M3 gcf;
M3 lpfSampleRate;
double lpfCutoffFrequency;
ma_lpf_config lpfConfig;
M3 oldSampleRateOut;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (sampleRateIn==0||sampleRateOut==0) {
Mr MA_INVALID_ARGS;
}
oldSampleRateOut=pResampler->config.sampleRateOut;
pResampler->config.sampleRateIn=sampleRateIn;
pResampler->config.sampleRateOut=sampleRateOut;
gcf=ma_gcf_u32(pResampler->config.sampleRateIn,pResampler->config.sampleRateOut);
pResampler->config.sampleRateIn /=gcf;
pResampler->config.sampleRateOut /=gcf;
if (pResampler->config.lpfOrder>MA_MAX_FILTER_ORDER) {
Mr MA_INVALID_ARGS;
}
lpfSampleRate=(M3)(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.Mh,lpfSampleRate,lpfCutoffFrequency,pResampler->config.lpfOrder);
if (isResamplerAlreadyInitialized) {
Mf=ma_lpf_reinit(&lpfConfig,&pResampler->lpf);
} else {
Mf=ma_lpf_init_preallocated(&lpfConfig,ma_offset_ptr(pHeap,pHeapLayout->lpfOffset),&pResampler->lpf);
}
if (Mf !=Ms) {
Mr Mf;
}
pResampler->inAdvanceInt=pResampler->config.sampleRateIn / pResampler->config.sampleRateOut;
pResampler->inAdvanceFrac=pResampler->config.sampleRateIn % pResampler->config.sampleRateOut;
ma_linear_resampler_adjust_timer_for_new_rate(pResampler,oldSampleRateOut,pResampler->config.sampleRateOut);
Mr Ms;
}
static Me ma_linear_resampler_get_heap_layout(const ma_linear_resampler_config*Mo,ma_linear_resampler_heap_layout*pHeapLayout)
{
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->format !=ma_format_f32&&Mo->format !=ma_format_s16) {
Mr MA_INVALID_ARGS;
}
if (Mo->Mh==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->x0Offset=pHeapLayout->sizeInBytes;
if (Mo->format==ma_format_f32) {
pHeapLayout->sizeInBytes+=sizeof(float)*Mo->Mh;
} else {
pHeapLayout->sizeInBytes+=sizeof(ma_int16)*Mo->Mh;
}
pHeapLayout->x1Offset=pHeapLayout->sizeInBytes;
if (Mo->format==ma_format_f32) {
pHeapLayout->sizeInBytes+=sizeof(float)*Mo->Mh;
} else {
pHeapLayout->sizeInBytes+=sizeof(ma_int16)*Mo->Mh;
}
pHeapLayout->lpfOffset=ma_align_64(pHeapLayout->sizeInBytes);
{
Me Mf;
size_t lpfHeapSizeInBytes;
ma_lpf_config lpfConfig=ma_lpf_config_init(Mo->format,Mo->Mh,1,1,Mo->lpfOrder);
Mf=ma_lpf_get_heap_size(&lpfConfig,&lpfHeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=lpfHeapSizeInBytes;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_linear_resampler_get_heap_size(const ma_linear_resampler_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_linear_resampler_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_linear_resampler_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_linear_resampler_init_preallocated(const ma_linear_resampler_config*Mo,Mv*pHeap,ma_linear_resampler*pResampler)
{
Me Mf;
ma_linear_resampler_heap_layout heapLayout;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pResampler);
Mf=ma_linear_resampler_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pResampler->config=*Mo;
pResampler->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
if (Mo->format==ma_format_f32) {
pResampler->x0.f32=(float*)ma_offset_ptr(pHeap,heapLayout.x0Offset);
pResampler->x1.f32=(float*)ma_offset_ptr(pHeap,heapLayout.x1Offset);
} else {
pResampler->x0.s16=(ma_int16*)ma_offset_ptr(pHeap,heapLayout.x0Offset);
pResampler->x1.s16=(ma_int16*)ma_offset_ptr(pHeap,heapLayout.x1Offset);
}
Mf=ma_linear_resampler_set_rate_internal(pResampler,pHeap,&heapLayout,Mo->sampleRateIn,Mo->sampleRateOut,MA_FALSE);
if (Mf !=Ms) {
Mr Mf;
}
pResampler->inTimeInt=1;
pResampler->inTimeFrac=0;
Mr Ms;
}
MA_API Me ma_linear_resampler_init(const ma_linear_resampler_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_linear_resampler*pResampler)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_linear_resampler_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_linear_resampler_init_preallocated(Mo,pHeap,pResampler);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pResampler->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_linear_resampler_uninit(ma_linear_resampler*pResampler,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pResampler==NULL) {
Mr;
}
ma_lpf_uninit(&pResampler->lpf,pAllocationCallbacks);
if (pResampler->_ownsHeap) {
ma_free(pResampler->_pHeap,pAllocationCallbacks);
}
}
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;
Mr (ma_int16)(r>>shift);
}
static Mv ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler*pResampler,ma_int16*MA_RESTRICT pFrameOut)
{
M3 c;
M3 a;
const M3 Mh=pResampler->config.Mh;
const M3 shift=12;
MA_ASSERT(pResampler !=NULL);
MA_ASSERT(pFrameOut !=NULL);
a=(pResampler->inTimeFrac<<shift) / pResampler->config.sampleRateOut;
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
ma_int16 s=ma_linear_resampler_mix_s16(pResampler->x0.s16[c],pResampler->x1.s16[c],a,shift);
pFrameOut[c]=s;
}
}
static Mv ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler*pResampler,float*MA_RESTRICT pFrameOut)
{
M3 c;
float a;
const M3 Mh=pResampler->config.Mh;
MA_ASSERT(pResampler !=NULL);
MA_ASSERT(pFrameOut !=NULL);
a=(float)pResampler->inTimeFrac / pResampler->config.sampleRateOut;
MA_ASSUME(Mh>0);
for (c=0; c<Mh; c+=1) {
float s=ma_mix_f32_fast(pResampler->x0.f32[c],pResampler->x1.f32[c],a);
pFrameOut[c]=s;
}
}
static Me ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
const ma_int16*pFramesInS16; ma_int16*pFramesOutS16;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
MA_ASSERT(pResampler !=NULL);
MA_ASSERT(pFrameCountIn !=NULL);
MA_ASSERT(pFrameCountOut !=NULL);
pFramesInS16=(const ma_int16*)pFramesIn;
pFramesOutS16=( ma_int16*)pFramesOut;
frameCountIn=*pFrameCountIn;
frameCountOut=*pFrameCountOut;
framesProcessedIn=0;
framesProcessedOut=0;
while (framesProcessedOut<frameCountOut) {
while (pResampler->inTimeInt>0&&frameCountIn>framesProcessedIn) {
M3 iChannel;
if (pFramesInS16 !=NULL) {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.s16[iChannel]=pResampler->x1.s16[iChannel];
 pResampler->x1.s16[iChannel]=pFramesInS16[iChannel];
}
pFramesInS16+=pResampler->config.Mh;
} else {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.s16[iChannel]=pResampler->x1.s16[iChannel];
 pResampler->x1.s16[iChannel]=0;
}
}
if (pResampler->config.sampleRateIn !=pResampler->config.sampleRateOut) {
ma_lpf_process_pcm_frame_s16(&pResampler->lpf,pResampler->x1.s16,pResampler->x1.s16);
}
framesProcessedIn+=1;
pResampler->inTimeInt-=1;
}
if (pResampler->inTimeInt>0) {
break;
}
if (pFramesOutS16 !=NULL) {
MA_ASSERT(pResampler->inTimeInt==0);
ma_linear_resampler_interpolate_frame_s16(pResampler,pFramesOutS16);
pFramesOutS16+=pResampler->config.Mh;
}
framesProcessedOut+=1;
pResampler->inTimeInt+=pResampler->inAdvanceInt;
pResampler->inTimeFrac+=pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac>=pResampler->config.sampleRateOut) {
pResampler->inTimeFrac-=pResampler->config.sampleRateOut;
pResampler->inTimeInt+=1;
}
}
*pFrameCountIn=framesProcessedIn;
*pFrameCountOut=framesProcessedOut;
Mr Ms;
}
static Me ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
const ma_int16*pFramesInS16; ma_int16*pFramesOutS16;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
MA_ASSERT(pResampler !=NULL);
MA_ASSERT(pFrameCountIn !=NULL);
MA_ASSERT(pFrameCountOut !=NULL);
pFramesInS16=(const ma_int16*)pFramesIn;
pFramesOutS16=( ma_int16*)pFramesOut;
frameCountIn=*pFrameCountIn;
frameCountOut=*pFrameCountOut;
framesProcessedIn=0;
framesProcessedOut=0;
while (framesProcessedOut<frameCountOut) {
while (pResampler->inTimeInt>0&&frameCountIn>framesProcessedIn) {
M3 iChannel;
if (pFramesInS16 !=NULL) {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.s16[iChannel]=pResampler->x1.s16[iChannel];
 pResampler->x1.s16[iChannel]=pFramesInS16[iChannel];
}
pFramesInS16+=pResampler->config.Mh;
} else {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.s16[iChannel]=pResampler->x1.s16[iChannel];
 pResampler->x1.s16[iChannel]=0;
}
}
framesProcessedIn+=1;
pResampler->inTimeInt-=1;
}
if (pResampler->inTimeInt>0) {
break;
}
if (pFramesOutS16 !=NULL) {
MA_ASSERT(pResampler->inTimeInt==0);
ma_linear_resampler_interpolate_frame_s16(pResampler,pFramesOutS16);
if (pResampler->config.sampleRateIn !=pResampler->config.sampleRateOut) {
ma_lpf_process_pcm_frame_s16(&pResampler->lpf,pFramesOutS16,pFramesOutS16);
}
pFramesOutS16+=pResampler->config.Mh;
}
framesProcessedOut+=1;
pResampler->inTimeInt+=pResampler->inAdvanceInt;
pResampler->inTimeFrac+=pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac>=pResampler->config.sampleRateOut) {
pResampler->inTimeFrac-=pResampler->config.sampleRateOut;
pResampler->inTimeInt+=1;
}
}
*pFrameCountIn=framesProcessedIn;
*pFrameCountOut=framesProcessedOut;
Mr Ms;
}
static Me ma_linear_resampler_process_pcm_frames_s16(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
MA_ASSERT(pResampler !=NULL);
if (pResampler->config.sampleRateIn>pResampler->config.sampleRateOut) {
Mr ma_linear_resampler_process_pcm_frames_s16_downsample(pResampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
} else {
Mr ma_linear_resampler_process_pcm_frames_s16_upsample(pResampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
}
}
static Me ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
const float*pFramesInF32; float*pFramesOutF32;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
MA_ASSERT(pResampler !=NULL);
MA_ASSERT(pFrameCountIn !=NULL);
MA_ASSERT(pFrameCountOut !=NULL);
pFramesInF32=(const float*)pFramesIn;
pFramesOutF32=( float*)pFramesOut;
frameCountIn=*pFrameCountIn;
frameCountOut=*pFrameCountOut;
framesProcessedIn=0;
framesProcessedOut=0;
while (framesProcessedOut<frameCountOut) {
while (pResampler->inTimeInt>0&&frameCountIn>framesProcessedIn) {
M3 iChannel;
if (pFramesInF32 !=NULL) {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.f32[iChannel]=pResampler->x1.f32[iChannel];
 pResampler->x1.f32[iChannel]=pFramesInF32[iChannel];
}
pFramesInF32+=pResampler->config.Mh;
} else {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.f32[iChannel]=pResampler->x1.f32[iChannel];
 pResampler->x1.f32[iChannel]=0;
}
}
if (pResampler->config.sampleRateIn !=pResampler->config.sampleRateOut) {
ma_lpf_process_pcm_frame_f32(&pResampler->lpf,pResampler->x1.f32,pResampler->x1.f32);
}
framesProcessedIn+=1;
pResampler->inTimeInt-=1;
}
if (pResampler->inTimeInt>0) {
break;
}
if (pFramesOutF32 !=NULL) {
MA_ASSERT(pResampler->inTimeInt==0);
ma_linear_resampler_interpolate_frame_f32(pResampler,pFramesOutF32);
pFramesOutF32+=pResampler->config.Mh;
}
framesProcessedOut+=1;
pResampler->inTimeInt+=pResampler->inAdvanceInt;
pResampler->inTimeFrac+=pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac>=pResampler->config.sampleRateOut) {
pResampler->inTimeFrac-=pResampler->config.sampleRateOut;
pResampler->inTimeInt+=1;
}
}
*pFrameCountIn=framesProcessedIn;
*pFrameCountOut=framesProcessedOut;
Mr Ms;
}
static Me ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
const float*pFramesInF32; float*pFramesOutF32;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
MA_ASSERT(pResampler !=NULL);
MA_ASSERT(pFrameCountIn !=NULL);
MA_ASSERT(pFrameCountOut !=NULL);
pFramesInF32=(const float*)pFramesIn;
pFramesOutF32=( float*)pFramesOut;
frameCountIn=*pFrameCountIn;
frameCountOut=*pFrameCountOut;
framesProcessedIn=0;
framesProcessedOut=0;
while (framesProcessedOut<frameCountOut) {
while (pResampler->inTimeInt>0&&frameCountIn>framesProcessedIn) {
M3 iChannel;
if (pFramesInF32 !=NULL) {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.f32[iChannel]=pResampler->x1.f32[iChannel];
 pResampler->x1.f32[iChannel]=pFramesInF32[iChannel];
}
pFramesInF32+=pResampler->config.Mh;
} else {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
 pResampler->x0.f32[iChannel]=pResampler->x1.f32[iChannel];
 pResampler->x1.f32[iChannel]=0;
}
}
framesProcessedIn+=1;
pResampler->inTimeInt-=1;
}
if (pResampler->inTimeInt>0) {
break;
}
if (pFramesOutF32 !=NULL) {
MA_ASSERT(pResampler->inTimeInt==0);
ma_linear_resampler_interpolate_frame_f32(pResampler,pFramesOutF32);
if (pResampler->config.sampleRateIn !=pResampler->config.sampleRateOut) {
ma_lpf_process_pcm_frame_f32(&pResampler->lpf,pFramesOutF32,pFramesOutF32);
}
pFramesOutF32+=pResampler->config.Mh;
}
framesProcessedOut+=1;
pResampler->inTimeInt+=pResampler->inAdvanceInt;
pResampler->inTimeFrac+=pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac>=pResampler->config.sampleRateOut) {
pResampler->inTimeFrac-=pResampler->config.sampleRateOut;
pResampler->inTimeInt+=1;
}
}
*pFrameCountIn=framesProcessedIn;
*pFrameCountOut=framesProcessedOut;
Mr Ms;
}
static Me ma_linear_resampler_process_pcm_frames_f32(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
MA_ASSERT(pResampler !=NULL);
if (pResampler->config.sampleRateIn>pResampler->config.sampleRateOut) {
Mr ma_linear_resampler_process_pcm_frames_f32_downsample(pResampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
} else {
Mr ma_linear_resampler_process_pcm_frames_f32_upsample(pResampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
}
}
MA_API Me ma_linear_resampler_process_pcm_frames(ma_linear_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
} if (pResampler->config.format==ma_format_s16) {
Mr ma_linear_resampler_process_pcm_frames_s16(pResampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
} else if (pResampler->config.format==ma_format_f32) {
Mr ma_linear_resampler_process_pcm_frames_f32(pResampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
} else {
MA_ASSERT(MA_FALSE);
Mr MA_INVALID_ARGS;
}
}
MA_API Me ma_linear_resampler_set_rate(ma_linear_resampler*pResampler,M3 sampleRateIn,M3 sampleRateOut)
{
Mr ma_linear_resampler_set_rate_internal(pResampler,NULL,NULL,sampleRateIn,sampleRateOut,MA_TRUE);
}
MA_API Me ma_linear_resampler_set_rate_ratio(ma_linear_resampler*pResampler,float ratioInOut)
{
M3 n;
M3 d;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (ratioInOut<=0) {
Mr MA_INVALID_ARGS;
}
d=1000000;
n=(M3)(ratioInOut*d);
if (n==0) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(n !=0);
Mr ma_linear_resampler_set_rate(pResampler,n,d);
}
MA_API M6 ma_linear_resampler_get_input_latency(const ma_linear_resampler*pResampler)
{
if (pResampler==NULL) {
Mr 0;
}
Mr 1+ma_lpf_get_latency(&pResampler->lpf);
}
MA_API M6 ma_linear_resampler_get_output_latency(const ma_linear_resampler*pResampler)
{
if (pResampler==NULL) {
Mr 0;
}
Mr ma_linear_resampler_get_input_latency(pResampler)*pResampler->config.sampleRateOut / pResampler->config.sampleRateIn;
}
MA_API Me ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler*pResampler,M6 outputFrameCount,M6*pInputFrameCount)
{
M6 inputFrameCount;
if (pInputFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
*pInputFrameCount=0;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (outputFrameCount==0) {
Mr Ms;
}
inputFrameCount=pResampler->inTimeInt;
outputFrameCount-=1;
inputFrameCount+=outputFrameCount*pResampler->inAdvanceInt;
inputFrameCount+=(pResampler->inTimeFrac+(outputFrameCount*pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
*pInputFrameCount=inputFrameCount;
Mr Ms;
}
MA_API Me ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler*pResampler,M6 inputFrameCount,M6*pOutputFrameCount)
{
M6 outputFrameCount;
M6 preliminaryInputFrameCountFromFrac;
M6 preliminaryInputFrameCount;
if (pOutputFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
*pOutputFrameCount=0;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
outputFrameCount=(inputFrameCount*pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn;
preliminaryInputFrameCountFromFrac=(pResampler->inTimeFrac+outputFrameCount*pResampler->inAdvanceFrac) / pResampler->config.sampleRateOut;
preliminaryInputFrameCount=(pResampler->inTimeInt+outputFrameCount*pResampler->inAdvanceInt )+preliminaryInputFrameCountFromFrac;
if (preliminaryInputFrameCount<=inputFrameCount) {
outputFrameCount+=1;
}
*pOutputFrameCount=outputFrameCount;
Mr Ms;
}
MA_API Me ma_linear_resampler_reset(ma_linear_resampler*pResampler)
{
M3 iChannel;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
pResampler->inTimeInt=1;
pResampler->inTimeFrac=0;
if (pResampler->config.format==ma_format_f32) {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
pResampler->x0.f32[iChannel]=0;
pResampler->x1.f32[iChannel]=0;
}
} else {
for (iChannel=0; iChannel<pResampler->config.Mh; iChannel+=1) {
pResampler->x0.s16[iChannel]=0;
pResampler->x1.s16[iChannel]=0;
}
}
ma_lpf_clear_cache(&pResampler->lpf);
Mr Ms;
}
static ma_linear_resampler_config ma_resampling_backend_get_config__linear(const ma_resampler_config*Mo)
{
ma_linear_resampler_config linearConfig;
linearConfig=ma_linear_resampler_config_init(Mo->format,Mo->Mh,Mo->sampleRateIn,Mo->sampleRateOut);
linearConfig.lpfOrder=Mo->linear.lpfOrder;
Mr linearConfig;
}
static Me ma_resampling_backend_get_heap_size__linear(Mv*pUserData,const ma_resampler_config*Mo,size_t*pHeapSizeInBytes)
{
ma_linear_resampler_config linearConfig;
(Mv)pUserData;
linearConfig=ma_resampling_backend_get_config__linear(Mo);
Mr ma_linear_resampler_get_heap_size(&linearConfig,pHeapSizeInBytes);
}
static Me ma_resampling_backend_init__linear(Mv*pUserData,const ma_resampler_config*Mo,Mv*pHeap,ma_resampling_backend**ppBackend)
{
ma_resampler*pResampler=(ma_resampler*)pUserData;
Me Mf;
ma_linear_resampler_config linearConfig;
(Mv)pUserData;
linearConfig=ma_resampling_backend_get_config__linear(Mo);
Mf=ma_linear_resampler_init_preallocated(&linearConfig,pHeap,&pResampler->state.linear);
if (Mf !=Ms) {
Mr Mf;
}
*ppBackend=&pResampler->state.linear;
Mr Ms;
}
static Mv ma_resampling_backend_uninit__linear(Mv*pUserData,ma_resampling_backend*pBackend,const ma_allocation_callbacks*pAllocationCallbacks)
{
(Mv)pUserData;
ma_linear_resampler_uninit((ma_linear_resampler*)pBackend,pAllocationCallbacks);
}
static Me ma_resampling_backend_process__linear(Mv*pUserData,ma_resampling_backend*pBackend,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
(Mv)pUserData;
Mr ma_linear_resampler_process_pcm_frames((ma_linear_resampler*)pBackend,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
}
static Me ma_resampling_backend_set_rate__linear(Mv*pUserData,ma_resampling_backend*pBackend,M3 sampleRateIn,M3 sampleRateOut)
{
(Mv)pUserData;
Mr ma_linear_resampler_set_rate((ma_linear_resampler*)pBackend,sampleRateIn,sampleRateOut);
}
static M6 ma_resampling_backend_get_input_latency__linear(Mv*pUserData,const ma_resampling_backend*pBackend)
{
(Mv)pUserData;
Mr ma_linear_resampler_get_input_latency((const ma_linear_resampler*)pBackend);
}
static M6 ma_resampling_backend_get_output_latency__linear(Mv*pUserData,const ma_resampling_backend*pBackend)
{
(Mv)pUserData;
Mr ma_linear_resampler_get_output_latency((const ma_linear_resampler*)pBackend);
}
static Me ma_resampling_backend_get_required_input_frame_count__linear(Mv*pUserData,const ma_resampling_backend*pBackend,M6 outputFrameCount,M6*pInputFrameCount)
{
(Mv)pUserData;
Mr ma_linear_resampler_get_required_input_frame_count((const ma_linear_resampler*)pBackend,outputFrameCount,pInputFrameCount);
}
static Me ma_resampling_backend_get_expected_output_frame_count__linear(Mv*pUserData,const ma_resampling_backend*pBackend,M6 inputFrameCount,M6*pOutputFrameCount)
{
(Mv)pUserData;
Mr ma_linear_resampler_get_expected_output_frame_count((const ma_linear_resampler*)pBackend,inputFrameCount,pOutputFrameCount);
}
static Me ma_resampling_backend_reset__linear(Mv*pUserData,ma_resampling_backend*pBackend)
{
(Mv)pUserData;
Mr ma_linear_resampler_reset((ma_linear_resampler*)pBackend);
}
static ma_resampling_backend_vtable g_ma_linear_resampler_vtable=
{
ma_resampling_backend_get_heap_size__linear,ma_resampling_backend_init__linear,ma_resampling_backend_uninit__linear,ma_resampling_backend_process__linear,ma_resampling_backend_set_rate__linear,ma_resampling_backend_get_input_latency__linear,ma_resampling_backend_get_output_latency__linear,ma_resampling_backend_get_required_input_frame_count__linear,ma_resampling_backend_get_expected_output_frame_count__linear,ma_resampling_backend_reset__linear
};
MA_API ma_resampler_config ma_resampler_config_init(ma_format format,M3 Mh,M3 sampleRateIn,M3 sampleRateOut,ma_resample_algorithm algorithm)
{
ma_resampler_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRateIn=sampleRateIn;
config.sampleRateOut=sampleRateOut;
config.algorithm=algorithm;
config.linear.lpfOrder=ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER,MA_MAX_FILTER_ORDER);
Mr config;
}
static Me ma_resampler_get_vtable(const ma_resampler_config*Mo,ma_resampler*pResampler,ma_resampling_backend_vtable**ppVTable,Mv**ppUserData)
{
MA_ASSERT(Mo !=NULL);
MA_ASSERT(ppVTable !=NULL);
MA_ASSERT(ppUserData !=NULL);
*ppVTable=NULL;
*ppUserData=NULL;
switch (Mo->algorithm)
{
case ma_resample_algorithm_linear:
{
*ppVTable=&g_ma_linear_resampler_vtable;
*ppUserData=pResampler;
} break;
case ma_resample_algorithm_custom:
{
*ppVTable=Mo->pBackendVTable;
*ppUserData=Mo->pBackendUserData;
} break;
default:Mr MA_INVALID_ARGS;
}
Mr Ms;
}
MA_API Me ma_resampler_get_heap_size(const ma_resampler_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_resampling_backend_vtable*pVTable;
Mv*pVTableUserData;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_resampler_get_vtable(Mo,NULL,&pVTable,&pVTableUserData);
if (Mf !=Ms) {
Mr Mf;
}
if (pVTable==NULL||pVTable->onGetHeapSize==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mf=pVTable->onGetHeapSize(pVTableUserData,Mo,pHeapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_resampler_init_preallocated(const ma_resampler_config*Mo,Mv*pHeap,ma_resampler*pResampler)
{
Me Mf;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pResampler);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
pResampler->_pHeap=pHeap;
pResampler->format=Mo->format;
pResampler->Mh=Mo->Mh;
pResampler->sampleRateIn=Mo->sampleRateIn;
pResampler->sampleRateOut=Mo->sampleRateOut;
Mf=ma_resampler_get_vtable(Mo,pResampler,&pResampler->pBackendVTable,&pResampler->pBackendUserData);
if (Mf !=Ms) {
Mr Mf;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onInit==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mf=pResampler->pBackendVTable->onInit(pResampler->pBackendUserData,Mo,pHeap,&pResampler->pBackend);
if (Mf !=Ms) {
Mr Mf;
}
Mr Ms;
}
MA_API Me ma_resampler_init(const ma_resampler_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_resampler*pResampler)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_resampler_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_resampler_init_preallocated(Mo,pHeap,pResampler);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pResampler->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_resampler_uninit(ma_resampler*pResampler,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pResampler==NULL) {
Mr;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onUninit==NULL) {
Mr;
}
pResampler->pBackendVTable->onUninit(pResampler->pBackendUserData,pResampler->pBackend,pAllocationCallbacks);
if (pResampler->_ownsHeap) {
ma_free(pResampler->_pHeap,pAllocationCallbacks);
}
}
MA_API Me ma_resampler_process_pcm_frames(ma_resampler*pResampler,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFrameCountOut==NULL&&pFrameCountIn==NULL) {
Mr MA_INVALID_ARGS;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onProcess==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData,pResampler->pBackend,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
}
MA_API Me ma_resampler_set_rate(ma_resampler*pResampler,M3 sampleRateIn,M3 sampleRateOut)
{
Me Mf;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (sampleRateIn==0||sampleRateOut==0) {
Mr MA_INVALID_ARGS;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onSetRate==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mf=pResampler->pBackendVTable->onSetRate(pResampler->pBackendUserData,pResampler->pBackend,sampleRateIn,sampleRateOut);
if (Mf !=Ms) {
Mr Mf;
}
pResampler->sampleRateIn=sampleRateIn;
pResampler->sampleRateOut=sampleRateOut;
Mr Ms;
}
MA_API Me ma_resampler_set_rate_ratio(ma_resampler*pResampler,float ratio)
{
M3 n;
M3 d;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (ratio<=0) {
Mr MA_INVALID_ARGS;
}
d=1000;
n=(M3)(ratio*d);
if (n==0) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(n !=0);
Mr ma_resampler_set_rate(pResampler,n,d);
}
MA_API M6 ma_resampler_get_input_latency(const ma_resampler*pResampler)
{
if (pResampler==NULL) {
Mr 0;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onGetInputLatency==NULL) {
Mr 0;
}
Mr pResampler->pBackendVTable->onGetInputLatency(pResampler->pBackendUserData,pResampler->pBackend);
}
MA_API M6 ma_resampler_get_output_latency(const ma_resampler*pResampler)
{
if (pResampler==NULL) {
Mr 0;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onGetOutputLatency==NULL) {
Mr 0;
}
Mr pResampler->pBackendVTable->onGetOutputLatency(pResampler->pBackendUserData,pResampler->pBackend);
}
MA_API Me ma_resampler_get_required_input_frame_count(const ma_resampler*pResampler,M6 outputFrameCount,M6*pInputFrameCount)
{
if (pInputFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
*pInputFrameCount=0;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onGetRequiredInputFrameCount==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pResampler->pBackendVTable->onGetRequiredInputFrameCount(pResampler->pBackendUserData,pResampler->pBackend,outputFrameCount,pInputFrameCount);
}
MA_API Me ma_resampler_get_expected_output_frame_count(const ma_resampler*pResampler,M6 inputFrameCount,M6*pOutputFrameCount)
{
if (pOutputFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
*pOutputFrameCount=0;
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onGetExpectedOutputFrameCount==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pResampler->pBackendVTable->onGetExpectedOutputFrameCount(pResampler->pBackendUserData,pResampler->pBackend,inputFrameCount,pOutputFrameCount);
}
MA_API Me ma_resampler_reset(ma_resampler*pResampler)
{
if (pResampler==NULL) {
Mr MA_INVALID_ARGS;
}
if (pResampler->pBackendVTable==NULL||pResampler->pBackendVTable->onReset==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pResampler->pBackendVTable->onReset(pResampler->pBackendUserData,pResampler->pBackend);
}
#ifndef MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT
#define MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT 12
#endif
#define MA_PLANE_LEFT 0
#define MA_PLANE_RIGHT 1
#define MA_PLANE_FRONT 2
#define MA_PLANE_BACK 3
#define MA_PLANE_BOTTOM 4
#define MA_PLANE_TOP 5
static float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6]={
{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.5f,0.0f,0.5f,0.0f,0.0f,0.0f},{ 0.0f,0.5f,0.5f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,1.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.5f,0.0f,0.0f,0.5f,0.0f,0.0f},{ 0.0f,0.5f,0.0f,0.5f,0.0f,0.0f},{ 0.25f,0.0f,0.75f,0.0f,0.0f,0.0f},{ 0.0f,0.25f,0.75f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,1.0f,0.0f,0.0f},{ 1.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,1.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,1.0f},{ 0.33f,0.0f,0.33f,0.0f,0.0f,0.34f},{ 0.0f,0.0f,0.5f,0.0f,0.0f,0.5f},{ 0.0f,0.33f,0.33f,0.0f,0.0f,0.34f},{ 0.33f,0.0f,0.0f,0.33f,0.0f,0.34f},{ 0.0f,0.0f,0.0f,0.5f,0.0f,0.5f},{ 0.0f,0.33f,0.0f,0.33f,0.0f,0.34f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},{ 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f},};
static float ma_calculate_channel_position_rectangular_weight(ma_channel channelPositionA,ma_channel channelPositionB)
{
float contribution=
g_maChannelPlaneRatios[channelPositionA][0]*g_maChannelPlaneRatios[channelPositionB][0]+
g_maChannelPlaneRatios[channelPositionA][1]*g_maChannelPlaneRatios[channelPositionB][1]+
g_maChannelPlaneRatios[channelPositionA][2]*g_maChannelPlaneRatios[channelPositionB][2]+
g_maChannelPlaneRatios[channelPositionA][3]*g_maChannelPlaneRatios[channelPositionB][3]+
g_maChannelPlaneRatios[channelPositionA][4]*g_maChannelPlaneRatios[channelPositionB][4]+
g_maChannelPlaneRatios[channelPositionA][5]*g_maChannelPlaneRatios[channelPositionB][5];
Mr contribution;
}
MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format,M3 channelsIn,const ma_channel*pChannelMapIn,M3 channelsOut,const ma_channel*pChannelMapOut,ma_channel_mix_mode mixingMode)
{
ma_channel_converter_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.channelsIn=channelsIn;
config.channelsOut=channelsOut;
config.pChannelMapIn=pChannelMapIn;
config.pChannelMapOut=pChannelMapOut;
config.mixingMode=mixingMode;
Mr config;
}
static ma_int32 ma_channel_converter_float_to_fixed(float x)
{
Mr (ma_int32)(x*(1<<MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT));
}
static M3 ma_channel_map_get_spatial_channel_count(const ma_channel*pChannelMap,M3 Mh)
{
M3 spatialChannelCount=0;
M3 iChannel;
MA_ASSERT(pChannelMap !=NULL);
MA_ASSERT(Mh>0);
for (iChannel=0; iChannel<Mh;++iChannel) {
if (ma_is_spatial_channel_position(ma_channel_map_get_channel(pChannelMap,Mh,iChannel))) {
spatialChannelCount++;
}
}
Mr spatialChannelCount;
}
static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition)
{
int i;
if (channelPosition==MA_CHANNEL_NONE||channelPosition==MA_CHANNEL_MONO||channelPosition==MA_CHANNEL_LFE) {
Mr MA_FALSE;
}
if (channelPosition>=MA_CHANNEL_AUX_0&&channelPosition<=MA_CHANNEL_AUX_31) {
Mr MA_FALSE;
}
for (i=0; i<6;++i) {
if (g_maChannelPlaneRatios[channelPosition][i] !=0) {
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
static ma_bool32 ma_channel_map_is_passthrough(const ma_channel*pChannelMapIn,M3 channelsIn,const ma_channel*pChannelMapOut,M3 channelsOut)
{
if (channelsOut==channelsIn) {
Mr ma_channel_map_is_equal(pChannelMapOut,pChannelMapIn,channelsOut);
} else {
Mr MA_FALSE;
}
}
static ma_channel_conversion_path ma_channel_map_get_conversion_path(const ma_channel*pChannelMapIn,M3 channelsIn,const ma_channel*pChannelMapOut,M3 channelsOut,ma_channel_mix_mode mode)
{
if (ma_channel_map_is_passthrough(pChannelMapIn,channelsIn,pChannelMapOut,channelsOut)) {
Mr ma_channel_conversion_path_passthrough;
}
if (channelsOut==1&&(pChannelMapOut==NULL||pChannelMapOut[0]==MA_CHANNEL_MONO)) {
Mr ma_channel_conversion_path_mono_out;
}
if (channelsIn==1&&(pChannelMapIn==NULL||pChannelMapIn[0]==MA_CHANNEL_MONO)) {
Mr ma_channel_conversion_path_mono_in;
}
if (mode==ma_channel_mix_mode_custom_weights) {
Mr ma_channel_conversion_path_weights;
}
if (channelsIn==channelsOut) {
M3 iChannelIn;
ma_bool32 areAllChannelPositionsPresent=MA_TRUE;
for (iChannelIn=0; iChannelIn<channelsIn;++iChannelIn) {
ma_bool32 isInputChannelPositionInOutput=ma_channel_map_contains_channel_position(channelsOut,pChannelMapOut,ma_channel_map_get_channel(pChannelMapIn,channelsIn,iChannelIn));
if (!isInputChannelPositionInOutput) {
areAllChannelPositionsPresent=MA_FALSE;
break;
}
}
if (areAllChannelPositionsPresent) {
Mr ma_channel_conversion_path_shuffle;
}
}
Mr ma_channel_conversion_path_weights;
}
static Me ma_channel_map_build_shuffle_table(const ma_channel*pChannelMapIn,M3 channelCountIn,const ma_channel*pChannelMapOut,M3 channelCountOut,ma_uint8*pShuffleTable)
{
M3 iChannelIn;
M3 iChannelOut;
if (pShuffleTable==NULL||channelCountIn==0||channelCountOut==0) {
Mr MA_INVALID_ARGS;
}
for (iChannelOut=0; iChannelOut<channelCountOut; iChannelOut+=1) {
ma_channel channelOut;
pShuffleTable[iChannelOut]=MA_CHANNEL_INDEX_NULL;
channelOut=ma_channel_map_get_channel(pChannelMapOut,channelCountOut,iChannelOut);
for (iChannelIn=0; iChannelIn<channelCountIn; iChannelIn+=1) {
ma_channel channelIn;
channelIn=ma_channel_map_get_channel(pChannelMapIn,channelCountIn,iChannelIn);
if (channelOut==channelIn) {
pShuffleTable[iChannelOut]=(ma_uint8)iChannelIn;
break;
}
switch (channelOut)
{
case MA_CHANNEL_FRONT_LEFT:
case MA_CHANNEL_SIDE_LEFT:
{
 switch (channelIn) {
 case MA_CHANNEL_FRONT_LEFT:
 case MA_CHANNEL_SIDE_LEFT:
 {
 pShuffleTable[iChannelOut]=(ma_uint8)iChannelIn;
 } break;
 }
} break;
case MA_CHANNEL_FRONT_RIGHT:
case MA_CHANNEL_SIDE_RIGHT:
{
 switch (channelIn) {
 case MA_CHANNEL_FRONT_RIGHT:
 case MA_CHANNEL_SIDE_RIGHT:
 {
 pShuffleTable[iChannelOut]=(ma_uint8)iChannelIn;
 } break;
 }
} break;
default:break;
}
}
}
Mr Ms;
}
static Mv ma_channel_map_apply_shuffle_table_u8(ma_uint8*pFramesOut,M3 channelsOut,const ma_uint8*pFramesIn,M3 channelsIn,M6 frameCount,const ma_uint8*pShuffleTable)
{
M6 iFrame;
M3 iChannelOut;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
ma_uint8 iChannelIn=pShuffleTable[iChannelOut];
if (iChannelIn<channelsIn) {
pFramesOut[iChannelOut]=pFramesIn[iChannelIn];
} else {
pFramesOut[iChannelOut]=0;
}
}
pFramesOut+=channelsOut;
pFramesIn+=channelsIn;
}
}
static Mv ma_channel_map_apply_shuffle_table_s16(ma_int16*pFramesOut,M3 channelsOut,const ma_int16*pFramesIn,M3 channelsIn,M6 frameCount,const ma_uint8*pShuffleTable)
{
M6 iFrame;
M3 iChannelOut;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
ma_uint8 iChannelIn=pShuffleTable[iChannelOut];
if (iChannelIn<channelsIn) {
pFramesOut[iChannelOut]=pFramesIn[iChannelIn];
} else {
pFramesOut[iChannelOut]=0;
}
}
pFramesOut+=channelsOut;
pFramesIn+=channelsIn;
}
}
static Mv ma_channel_map_apply_shuffle_table_s24(ma_uint8*pFramesOut,M3 channelsOut,const ma_uint8*pFramesIn,M3 channelsIn,M6 frameCount,const ma_uint8*pShuffleTable)
{
M6 iFrame;
M3 iChannelOut;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
ma_uint8 iChannelIn=pShuffleTable[iChannelOut];
if (iChannelIn<channelsIn) {
pFramesOut[iChannelOut*3+0]=pFramesIn[iChannelIn*3+0];
pFramesOut[iChannelOut*3+1]=pFramesIn[iChannelIn*3+1];
pFramesOut[iChannelOut*3+2]=pFramesIn[iChannelIn*3+2];
} else {
pFramesOut[iChannelOut*3+0]=0;
} pFramesOut[iChannelOut*3+1]=0;
} pFramesOut[iChannelOut*3+2]=0;
pFramesOut+=channelsOut*3;
pFramesIn+=channelsIn*3;
}
}
static Mv ma_channel_map_apply_shuffle_table_s32(ma_int32*pFramesOut,M3 channelsOut,const ma_int32*pFramesIn,M3 channelsIn,M6 frameCount,const ma_uint8*pShuffleTable)
{
M6 iFrame;
M3 iChannelOut;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
ma_uint8 iChannelIn=pShuffleTable[iChannelOut];
if (iChannelIn<channelsIn) {
pFramesOut[iChannelOut]=pFramesIn[iChannelIn];
} else {
pFramesOut[iChannelOut]=0;
}
}
pFramesOut+=channelsOut;
pFramesIn+=channelsIn;
}
}
static Mv ma_channel_map_apply_shuffle_table_f32(float*pFramesOut,M3 channelsOut,const float*pFramesIn,M3 channelsIn,M6 frameCount,const ma_uint8*pShuffleTable)
{
M6 iFrame;
M3 iChannelOut;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
ma_uint8 iChannelIn=pShuffleTable[iChannelOut];
if (iChannelIn<channelsIn) {
pFramesOut[iChannelOut]=pFramesIn[iChannelIn];
} else {
pFramesOut[iChannelOut]=0;
}
}
pFramesOut+=channelsOut;
pFramesIn+=channelsIn;
}
}
static Me ma_channel_map_apply_shuffle_table(Mv*pFramesOut,M3 channelsOut,const Mv*pFramesIn,M3 channelsIn,M6 frameCount,const ma_uint8*pShuffleTable,ma_format format)
{
if (pFramesOut==NULL||pFramesIn==NULL||channelsOut==0||pShuffleTable==NULL) {
Mr MA_INVALID_ARGS;
}
switch (format)
{
case ma_format_u8:
{
ma_channel_map_apply_shuffle_table_u8((ma_uint8*)pFramesOut,channelsOut,(const ma_uint8*)pFramesIn,channelsIn,frameCount,pShuffleTable);
} break;
case ma_format_s16:
{
ma_channel_map_apply_shuffle_table_s16((ma_int16*)pFramesOut,channelsOut,(const ma_int16*)pFramesIn,channelsIn,frameCount,pShuffleTable);
} break;
case ma_format_s24:
{
ma_channel_map_apply_shuffle_table_s24((ma_uint8*)pFramesOut,channelsOut,(const ma_uint8*)pFramesIn,channelsIn,frameCount,pShuffleTable);
} break;
case ma_format_s32:
{
ma_channel_map_apply_shuffle_table_s32((ma_int32*)pFramesOut,channelsOut,(const ma_int32*)pFramesIn,channelsIn,frameCount,pShuffleTable);
} break;
case ma_format_f32:
{
ma_channel_map_apply_shuffle_table_f32((float*)pFramesOut,channelsOut,(const float*)pFramesIn,channelsIn,frameCount,pShuffleTable);
} break;
default:Mr MA_INVALID_ARGS;
}
Mr Ms;
}
static Me ma_channel_map_apply_mono_out_f32(float*pFramesOut,const float*pFramesIn,const ma_channel*pChannelMapIn,M3 channelsIn,M6 frameCount)
{
M6 iFrame;
M3 iChannelIn;
M3 accumulationCount;
if (pFramesOut==NULL||pFramesIn==NULL||channelsIn==0) {
Mr MA_INVALID_ARGS;
}
accumulationCount=0;
for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
if (ma_channel_map_get_channel(pChannelMapIn,channelsIn,iChannelIn) !=MA_CHANNEL_NONE) {
accumulationCount+=1;
}
}
if (accumulationCount>0) {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
float accumulation=0;
for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
ma_channel channelIn=ma_channel_map_get_channel(pChannelMapIn,channelsIn,iChannelIn);
if (channelIn !=MA_CHANNEL_NONE) {
 accumulation+=pFramesIn[iChannelIn];
}
}
pFramesOut[0]=accumulation / accumulationCount;
pFramesOut+=1;
pFramesIn+=channelsIn;
}
} else {
ma_silence_pcm_frames(pFramesOut,frameCount,ma_format_f32,1);
}
Mr Ms;
}
static Me ma_channel_map_apply_mono_in_f32(float*MA_RESTRICT pFramesOut,const ma_channel*pChannelMapOut,M3 channelsOut,const float*MA_RESTRICT pFramesIn,M6 frameCount,ma_mono_expansion_mode monoExpansionMode)
{
M6 iFrame;
M3 iChannelOut;
if (pFramesOut==NULL||channelsOut==0||pFramesIn==NULL) {
Mr MA_INVALID_ARGS;
}
switch (monoExpansionMode)
{
case ma_mono_expansion_mode_average:
{
float weight;
M3 validChannelCount=0;
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
if (channelOut !=MA_CHANNEL_NONE) {
 validChannelCount+=1;
}
}
weight=1.0f / validChannelCount;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 if (channelOut !=MA_CHANNEL_NONE) {
 pFramesOut[iChannelOut]=pFramesIn[0]*weight;
 }
}
pFramesOut+=channelsOut;
pFramesIn+=1;
}
} break;
case ma_mono_expansion_mode_stereo_only:
{
if (channelsOut>=2) {
M3 iChannelLeft=(M3)-1;
M3 iChannelRight=(M3)-1;
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 if (channelOut==MA_CHANNEL_SIDE_LEFT) {
 iChannelLeft=iChannelOut;
 }
 if (channelOut==MA_CHANNEL_SIDE_RIGHT) {
 iChannelRight=iChannelOut;
 }
}
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 if (channelOut==MA_CHANNEL_FRONT_LEFT) {
 iChannelLeft=iChannelOut;
 }
 if (channelOut==MA_CHANNEL_FRONT_RIGHT) {
 iChannelRight=iChannelOut;
 }
}
if (iChannelLeft !=(M3)-1&&iChannelRight !=(M3)-1) {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 if (channelOut !=MA_CHANNEL_NONE) {
 if (iChannelOut==iChannelLeft||iChannelOut==iChannelRight) {
 pFramesOut[iChannelOut]=pFramesIn[0];
 } else {
 pFramesOut[iChannelOut]=0.0f;
 }
 }
 }
 pFramesOut+=channelsOut;
 pFramesIn+=1;
 }
 break;
} else {
 goto default_handler;
}
} else {
goto default_handler;
}
};
case ma_mono_expansion_mode_duplicate:
default:
{
default_handler:
{
if (channelsOut<=MA_MAX_CHANNELS) {
 ma_bool32 hasEmptyChannel=MA_FALSE;
 ma_channel channelPositions[MA_MAX_CHANNELS];
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 channelPositions[iChannelOut]=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 if (channelPositions[iChannelOut]==MA_CHANNEL_NONE) {
 hasEmptyChannel=MA_TRUE;
 }
 }
 if (hasEmptyChannel==MA_FALSE) {
 if (channelsOut==2) {
 #if defined(MA_SUPPORT_SSE2)
 if (ma_has_sse2()) {
 M6 unrolledFrameCount=frameCount>>1;
 for (iFrame=0; iFrame<unrolledFrameCount; iFrame+=1) {
 __m128 in0=_mm_set1_ps(pFramesIn[iFrame*2+0]);
 __m128 in1=_mm_set1_ps(pFramesIn[iFrame*2+1]);
 _mm_storeu_ps(&pFramesOut[iFrame*4+0],_mm_shuffle_ps(in0,in1,_MM_SHUFFLE(0,0,0,0)));
 }
 iFrame=unrolledFrameCount<<1;
 goto generic_on_fastpath;
 } else
 #endif
 {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<2; iChannelOut+=1) {
 pFramesOut[iFrame*2+iChannelOut]=pFramesIn[iFrame];
 }
 }
 }
 } else if (channelsOut==6) {
 #if defined(MA_SUPPORT_SSE2)
 if (ma_has_sse2()) {
 M6 unrolledFrameCount=frameCount>>1;
 for (iFrame=0; iFrame<unrolledFrameCount; iFrame+=1) {
 __m128 in0=_mm_set1_ps(pFramesIn[iFrame*2+0]);
 __m128 in1=_mm_set1_ps(pFramesIn[iFrame*2+1]);
 _mm_storeu_ps(&pFramesOut[iFrame*12+0],in0);
 _mm_storeu_ps(&pFramesOut[iFrame*12+4],_mm_shuffle_ps(in0,in1,_MM_SHUFFLE(0,0,0,0)));
 _mm_storeu_ps(&pFramesOut[iFrame*12+8],in1);
 }
 iFrame=unrolledFrameCount<<1;
 goto generic_on_fastpath;
 } else
 #endif
 {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<6; iChannelOut+=1) {
 pFramesOut[iFrame*6+iChannelOut]=pFramesIn[iFrame];
 }
 }
 }
 } else if (channelsOut==8) {
 #if defined(MA_SUPPORT_SSE2)
 if (ma_has_sse2()) {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 __m128 in=_mm_set1_ps(pFramesIn[iFrame]);
 _mm_storeu_ps(&pFramesOut[iFrame*8+0],in);
 _mm_storeu_ps(&pFramesOut[iFrame*8+4],in);
 }
 } else
 #endif
 {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<8; iChannelOut+=1) {
 pFramesOut[iFrame*8+iChannelOut]=pFramesIn[iFrame];
 }
 }
 }
 } else {
 iFrame=0;
 #if defined(MA_SUPPORT_SSE2)
 generic_on_fastpath:
 #endif
 {
 for (; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 pFramesOut[iFrame*channelsOut+iChannelOut]=pFramesIn[iFrame];
 }
 }
 }
 }
 } else {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 if (channelPositions[iChannelOut] !=MA_CHANNEL_NONE) {
 pFramesOut[iFrame*channelsOut+iChannelOut]=pFramesIn[iFrame];
 }
 }
 }
 }
} else {
 for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 if (channelOut !=MA_CHANNEL_NONE) {
 pFramesOut[iFrame*channelsOut+iChannelOut]=pFramesIn[iFrame];
 }
 }
 }
}
}
} break;
}
Mr Ms;
}
static Mv ma_channel_map_apply_f32(float*pFramesOut,const ma_channel*pChannelMapOut,M3 channelsOut,const float*pFramesIn,const ma_channel*pChannelMapIn,M3 channelsIn,M6 frameCount,ma_channel_mix_mode mode,ma_mono_expansion_mode monoExpansionMode)
{
ma_channel_conversion_path conversionPath=ma_channel_map_get_conversion_path(pChannelMapIn,channelsIn,pChannelMapOut,channelsOut,mode);
if (conversionPath==ma_channel_conversion_path_passthrough) {
ma_copy_pcm_frames(pFramesOut,pFramesIn,frameCount,ma_format_f32,channelsOut);
Mr;
}
if (conversionPath==ma_channel_conversion_path_mono_out) {
ma_channel_map_apply_mono_out_f32(pFramesOut,pFramesIn,pChannelMapIn,channelsIn,frameCount);
Mr;
}
if (conversionPath==ma_channel_conversion_path_mono_in) {
ma_channel_map_apply_mono_in_f32(pFramesOut,pChannelMapOut,channelsOut,pFramesIn,frameCount,monoExpansionMode);
Mr;
}
if (channelsOut<=MA_MAX_CHANNELS) {
Me Mf;
if (mode==ma_channel_mix_mode_simple) {
ma_channel shuffleTable[MA_MAX_CHANNELS];
Mf=ma_channel_map_build_shuffle_table(pChannelMapIn,channelsIn,pChannelMapOut,channelsOut,shuffleTable);
if (Mf !=Ms) {
Mr;
}
Mf=ma_channel_map_apply_shuffle_table(pFramesOut,channelsOut,pFramesIn,channelsIn,frameCount,shuffleTable,ma_format_f32);
if (Mf !=Ms) {
Mr;
}
} else {
M3 iFrame;
M3 iChannelOut;
M3 iChannelIn;
float weights[32][32];
if (channelsIn<=ma_countof(weights)&&channelsOut<=ma_countof(weights)) {
for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
 ma_channel channelIn=ma_channel_map_get_channel(pChannelMapIn,channelsIn,iChannelIn);
 weights[iChannelOut][iChannelIn]=ma_calculate_channel_position_rectangular_weight(channelOut,channelIn);
 }
}
iFrame=0;
if (channelsOut==8) {
 if (channelsIn==2) {
 for (; iFrame<frameCount; iFrame+=1) {
 float accumulation[8]={ 0,0,0,0,0,0,0,0 };
 accumulation[0]+=pFramesIn[iFrame*2+0]*weights[0][0];
 accumulation[1]+=pFramesIn[iFrame*2+0]*weights[1][0];
 accumulation[2]+=pFramesIn[iFrame*2+0]*weights[2][0];
 accumulation[3]+=pFramesIn[iFrame*2+0]*weights[3][0];
 accumulation[4]+=pFramesIn[iFrame*2+0]*weights[4][0];
 accumulation[5]+=pFramesIn[iFrame*2+0]*weights[5][0];
 accumulation[6]+=pFramesIn[iFrame*2+0]*weights[6][0];
 accumulation[7]+=pFramesIn[iFrame*2+0]*weights[7][0];
 accumulation[0]+=pFramesIn[iFrame*2+1]*weights[0][1];
 accumulation[1]+=pFramesIn[iFrame*2+1]*weights[1][1];
 accumulation[2]+=pFramesIn[iFrame*2+1]*weights[2][1];
 accumulation[3]+=pFramesIn[iFrame*2+1]*weights[3][1];
 accumulation[4]+=pFramesIn[iFrame*2+1]*weights[4][1];
 accumulation[5]+=pFramesIn[iFrame*2+1]*weights[5][1];
 accumulation[6]+=pFramesIn[iFrame*2+1]*weights[6][1];
 accumulation[7]+=pFramesIn[iFrame*2+1]*weights[7][1];
 pFramesOut[iFrame*8+0]=accumulation[0];
 pFramesOut[iFrame*8+1]=accumulation[1];
 pFramesOut[iFrame*8+2]=accumulation[2];
 pFramesOut[iFrame*8+3]=accumulation[3];
 pFramesOut[iFrame*8+4]=accumulation[4];
 pFramesOut[iFrame*8+5]=accumulation[5];
 pFramesOut[iFrame*8+6]=accumulation[6];
 pFramesOut[iFrame*8+7]=accumulation[7];
 }
 } else {
 for (; iFrame<frameCount; iFrame+=1) {
 float accumulation[8]={ 0,0,0,0,0,0,0,0 };
 for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
 accumulation[0]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[0][iChannelIn];
 accumulation[1]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[1][iChannelIn];
 accumulation[2]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[2][iChannelIn];
 accumulation[3]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[3][iChannelIn];
 accumulation[4]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[4][iChannelIn];
 accumulation[5]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[5][iChannelIn];
 accumulation[6]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[6][iChannelIn];
 accumulation[7]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[7][iChannelIn];
 }
 pFramesOut[iFrame*8+0]=accumulation[0];
 pFramesOut[iFrame*8+1]=accumulation[1];
 pFramesOut[iFrame*8+2]=accumulation[2];
 pFramesOut[iFrame*8+3]=accumulation[3];
 pFramesOut[iFrame*8+4]=accumulation[4];
 pFramesOut[iFrame*8+5]=accumulation[5];
 pFramesOut[iFrame*8+6]=accumulation[6];
 pFramesOut[iFrame*8+7]=accumulation[7];
 }
 }
} else if (channelsOut==6) {
 for (; iFrame<frameCount; iFrame+=1) {
 float accumulation[12]={ 0,0,0,0,0,0,0,0,0,0,0,0 };
 for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
 accumulation[0]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[0][iChannelIn];
 accumulation[1]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[1][iChannelIn];
 accumulation[2]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[2][iChannelIn];
 accumulation[3]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[3][iChannelIn];
 accumulation[4]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[4][iChannelIn];
 accumulation[5]+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[5][iChannelIn];
 }
 pFramesOut[iFrame*6+0]=accumulation[0];
 pFramesOut[iFrame*6+1]=accumulation[1];
 pFramesOut[iFrame*6+2]=accumulation[2];
 pFramesOut[iFrame*6+3]=accumulation[3];
 pFramesOut[iFrame*6+4]=accumulation[4];
 pFramesOut[iFrame*6+5]=accumulation[5];
 }
}
for (; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 float accumulation=0;
 for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
 accumulation+=pFramesIn[iFrame*channelsIn+iChannelIn]*weights[iChannelOut][iChannelIn];
 }
 pFramesOut[iFrame*channelsOut+iChannelOut]=accumulation;
 }
}
} else {
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
 for (iChannelOut=0; iChannelOut<channelsOut; iChannelOut+=1) {
 float accumulation=0;
 ma_channel channelOut=ma_channel_map_get_channel(pChannelMapOut,channelsOut,iChannelOut);
 for (iChannelIn=0; iChannelIn<channelsIn; iChannelIn+=1) {
 ma_channel channelIn=ma_channel_map_get_channel(pChannelMapIn,channelsIn,iChannelIn);
 accumulation+=pFramesIn[iFrame*channelsIn+iChannelIn]*ma_calculate_channel_position_rectangular_weight(channelOut,channelIn);
 }
 pFramesOut[iFrame*channelsOut+iChannelOut]=accumulation;
 }
}
}
}
} else {
ma_silence_pcm_frames(pFramesOut,frameCount,ma_format_f32,channelsOut);
}
}
typedef struct
{
size_t sizeInBytes;
size_t channelMapInOffset;
size_t channelMapOutOffset;
size_t shuffleTableOffset;
size_t weightsOffset;
} ma_channel_converter_heap_layout;
static ma_channel_conversion_path ma_channel_converter_config_get_conversion_path(const ma_channel_converter_config*Mo)
{
Mr ma_channel_map_get_conversion_path(Mo->pChannelMapIn,Mo->channelsIn,Mo->pChannelMapOut,Mo->channelsOut,Mo->mixingMode);
}
static Me ma_channel_converter_get_heap_layout(const ma_channel_converter_config*Mo,ma_channel_converter_heap_layout*pHeapLayout)
{
ma_channel_conversion_path conversionPath;
MA_ASSERT(pHeapLayout !=NULL);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->channelsIn==0||Mo->channelsOut==0) {
Mr MA_INVALID_ARGS;
}
if (!ma_channel_map_is_valid(Mo->pChannelMapIn,Mo->channelsIn)) {
Mr MA_INVALID_ARGS;
}
if (!ma_channel_map_is_valid(Mo->pChannelMapOut,Mo->channelsOut)) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->channelMapInOffset=pHeapLayout->sizeInBytes;
if (Mo->pChannelMapIn !=NULL) {
pHeapLayout->sizeInBytes+=sizeof(ma_channel)*Mo->channelsIn;
}
pHeapLayout->channelMapOutOffset=pHeapLayout->sizeInBytes;
if (Mo->pChannelMapOut !=NULL) {
pHeapLayout->sizeInBytes+=sizeof(ma_channel)*Mo->channelsOut;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
conversionPath=ma_channel_converter_config_get_conversion_path(Mo);
pHeapLayout->shuffleTableOffset=pHeapLayout->sizeInBytes;
if (conversionPath==ma_channel_conversion_path_shuffle) {
pHeapLayout->sizeInBytes+=sizeof(ma_uint8)*Mo->channelsOut;
}
pHeapLayout->weightsOffset=pHeapLayout->sizeInBytes;
if (conversionPath==ma_channel_conversion_path_weights) {
pHeapLayout->sizeInBytes+=sizeof(float*)*Mo->channelsIn;
pHeapLayout->sizeInBytes+=sizeof(float )*Mo->channelsIn*Mo->channelsOut;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_channel_converter_get_heap_size(const ma_channel_converter_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_channel_converter_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_channel_converter_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_channel_converter_init_preallocated(const ma_channel_converter_config*Mo,Mv*pHeap,ma_channel_converter*pConverter)
{
Me Mf;
ma_channel_converter_heap_layout heapLayout;
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pConverter);
Mf=ma_channel_converter_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pConverter->_pHeap=pHeap;
MA_ZERO_MEMORY(pConverter->_pHeap,heapLayout.sizeInBytes);
pConverter->format=Mo->format;
pConverter->channelsIn=Mo->channelsIn;
pConverter->channelsOut=Mo->channelsOut;
pConverter->mixingMode=Mo->mixingMode;
if (Mo->pChannelMapIn !=NULL) {
pConverter->pChannelMapIn=(ma_channel*)ma_offset_ptr(pHeap,heapLayout.channelMapInOffset);
ma_channel_map_copy_or_default(pConverter->pChannelMapIn,Mo->channelsIn,Mo->pChannelMapIn,Mo->channelsIn);
} else {
pConverter->pChannelMapIn=NULL;
}
if (Mo->pChannelMapOut !=NULL) {
pConverter->pChannelMapOut=(ma_channel*)ma_offset_ptr(pHeap,heapLayout.channelMapOutOffset);
ma_channel_map_copy_or_default(pConverter->pChannelMapOut,Mo->channelsOut,Mo->pChannelMapOut,Mo->channelsOut);
} else {
pConverter->pChannelMapOut=NULL;
}
pConverter->conversionPath=ma_channel_converter_config_get_conversion_path(Mo);
if (pConverter->conversionPath==ma_channel_conversion_path_shuffle) {
pConverter->pShuffleTable=(ma_uint8*)ma_offset_ptr(pHeap,heapLayout.shuffleTableOffset);
ma_channel_map_build_shuffle_table(pConverter->pChannelMapIn,pConverter->channelsIn,pConverter->pChannelMapOut,pConverter->channelsOut,pConverter->pShuffleTable);
}
if (pConverter->conversionPath==ma_channel_conversion_path_weights) {
M3 iChannelIn;
M3 iChannelOut;
if (pConverter->format==ma_format_f32) {
pConverter->weights.f32=(float**)ma_offset_ptr(pHeap,heapLayout.weightsOffset);
for (iChannelIn=0; iChannelIn<pConverter->channelsIn; iChannelIn+=1) {
pConverter->weights.f32[iChannelIn]=(float*)ma_offset_ptr(pHeap,heapLayout.weightsOffset+((sizeof(float*)*pConverter->channelsIn)+(sizeof(float)*pConverter->channelsOut*iChannelIn)));
}
} else {
pConverter->weights.s16=(ma_int32**)ma_offset_ptr(pHeap,heapLayout.weightsOffset);
for (iChannelIn=0; iChannelIn<pConverter->channelsIn; iChannelIn+=1) {
pConverter->weights.s16[iChannelIn]=(ma_int32*)ma_offset_ptr(pHeap,heapLayout.weightsOffset+((sizeof(ma_int32*)*pConverter->channelsIn)+(sizeof(ma_int32)*pConverter->channelsOut*iChannelIn)));
}
}
for (iChannelIn=0; iChannelIn<pConverter->channelsIn; iChannelIn+=1) {
for (iChannelOut=0; iChannelOut<pConverter->channelsOut; iChannelOut+=1) {
if (pConverter->format==ma_format_f32) {
 pConverter->weights.f32[iChannelIn][iChannelOut]=0.0f;
} else {
 pConverter->weights.s16[iChannelIn][iChannelOut]=0;
}
}
}
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
ma_channel channelPosIn=ma_channel_map_get_channel(pConverter->pChannelMapIn,pConverter->channelsIn,iChannelIn);
for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
ma_channel channelPosOut=ma_channel_map_get_channel(pConverter->pChannelMapOut,pConverter->channelsOut,iChannelOut);
if (channelPosIn==channelPosOut) {
 float weight=1;
 if (pConverter->format==ma_format_f32) {
 pConverter->weights.f32[iChannelIn][iChannelOut]=weight;
 } else {
 pConverter->weights.s16[iChannelIn][iChannelOut]=ma_channel_converter_float_to_fixed(weight);
 }
}
}
}
switch (pConverter->mixingMode)
{
case ma_channel_mix_mode_custom_weights:
{
if (Mo->ppWeights==NULL) {
 Mr MA_INVALID_ARGS;
}
for (iChannelIn=0; iChannelIn<pConverter->channelsIn; iChannelIn+=1) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut; iChannelOut+=1) {
 float weight=Mo->ppWeights[iChannelIn][iChannelOut];
 if (pConverter->format==ma_format_f32) {
 pConverter->weights.f32[iChannelIn][iChannelOut]=weight;
 } else {
 pConverter->weights.s16[iChannelIn][iChannelOut]=ma_channel_converter_float_to_fixed(weight);
 }
 }
}
} break;
case ma_channel_mix_mode_simple:
{
} break;
case ma_channel_mix_mode_rectangular:
default:
{
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 ma_channel channelPosIn=ma_channel_map_get_channel(pConverter->pChannelMapIn,pConverter->channelsIn,iChannelIn);
 if (ma_is_spatial_channel_position(channelPosIn)) {
 if (!ma_channel_map_contains_channel_position(pConverter->channelsOut,pConverter->pChannelMapOut,channelPosIn)) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 ma_channel channelPosOut=ma_channel_map_get_channel(pConverter->pChannelMapOut,pConverter->channelsOut,iChannelOut);
 if (ma_is_spatial_channel_position(channelPosOut)) {
 float weight=0;
 if (pConverter->mixingMode==ma_channel_mix_mode_rectangular) {
 weight=ma_calculate_channel_position_rectangular_weight(channelPosIn,channelPosOut);
 }
 if (pConverter->format==ma_format_f32) {
 if (pConverter->weights.f32[iChannelIn][iChannelOut]==0) {
 pConverter->weights.f32[iChannelIn][iChannelOut]=weight;
 }
 } else {
 if (pConverter->weights.s16[iChannelIn][iChannelOut]==0) {
 pConverter->weights.s16[iChannelIn][iChannelOut]=ma_channel_converter_float_to_fixed(weight);
 }
 }
 }
 }
 }
 }
}
for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 ma_channel channelPosOut=ma_channel_map_get_channel(pConverter->pChannelMapOut,pConverter->channelsOut,iChannelOut);
 if (ma_is_spatial_channel_position(channelPosOut)) {
 if (!ma_channel_map_contains_channel_position(pConverter->channelsIn,pConverter->pChannelMapIn,channelPosOut)) {
 for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 ma_channel channelPosIn=ma_channel_map_get_channel(pConverter->pChannelMapIn,pConverter->channelsIn,iChannelIn);
 if (ma_is_spatial_channel_position(channelPosIn)) {
 float weight=0;
 if (pConverter->mixingMode==ma_channel_mix_mode_rectangular) {
 weight=ma_calculate_channel_position_rectangular_weight(channelPosIn,channelPosOut);
 }
 if (pConverter->format==ma_format_f32) {
 if (pConverter->weights.f32[iChannelIn][iChannelOut]==0) {
 pConverter->weights.f32[iChannelIn][iChannelOut]=weight;
 }
 } else {
 if (pConverter->weights.s16[iChannelIn][iChannelOut]==0) {
 pConverter->weights.s16[iChannelIn][iChannelOut]=ma_channel_converter_float_to_fixed(weight);
 }
 }
 }
 }
 }
 }
}
if (Mo->calculateLFEFromSpatialChannels) {
 if (!ma_channel_map_contains_channel_position(pConverter->channelsIn,pConverter->pChannelMapIn,MA_CHANNEL_LFE)) {
 M3 spatialChannelCount=ma_channel_map_get_spatial_channel_count(pConverter->pChannelMapIn,pConverter->channelsIn);
 M3 iChannelOutLFE;
 if (spatialChannelCount>0&&ma_channel_map_find_channel_position(pConverter->channelsOut,pConverter->pChannelMapOut,MA_CHANNEL_LFE,&iChannelOutLFE)) {
 const float weightForLFE=1.0f / spatialChannelCount;
 for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 const ma_channel channelPosIn=ma_channel_map_get_channel(pConverter->pChannelMapIn,pConverter->channelsIn,iChannelIn);
 if (ma_is_spatial_channel_position(channelPosIn)) {
 if (pConverter->format==ma_format_f32) {
 if (pConverter->weights.f32[iChannelIn][iChannelOutLFE]==0) {
 pConverter->weights.f32[iChannelIn][iChannelOutLFE]=weightForLFE;
 }
 } else {
 if (pConverter->weights.s16[iChannelIn][iChannelOutLFE]==0) {
 pConverter->weights.s16[iChannelIn][iChannelOutLFE]=ma_channel_converter_float_to_fixed(weightForLFE);
 }
 }
 }
 }
 }
 }
}
} break;
}
}
Mr Ms;
}
MA_API Me ma_channel_converter_init(const ma_channel_converter_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_channel_converter*pConverter)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_channel_converter_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_channel_converter_init_preallocated(Mo,pHeap,pConverter);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pConverter->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_channel_converter_uninit(ma_channel_converter*pConverter,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pConverter==NULL) {
Mr;
}
if (pConverter->_ownsHeap) {
ma_free(pConverter->_pHeap,pAllocationCallbacks);
}
}
static Me ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pFramesOut !=NULL);
MA_ASSERT(pFramesIn !=NULL);
ma_copy_memory_64(pFramesOut,pFramesIn,frameCount*ma_get_bytes_per_frame(pConverter->format,pConverter->channelsOut));
Mr Ms;
}
static Me ma_channel_converter_process_pcm_frames__shuffle(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pFramesOut !=NULL);
MA_ASSERT(pFramesIn !=NULL);
MA_ASSERT(pConverter->channelsIn==pConverter->channelsOut);
Mr ma_channel_map_apply_shuffle_table(pFramesOut,pConverter->channelsOut,pFramesIn,pConverter->channelsIn,frameCount,pConverter->pShuffleTable,pConverter->format);
}
static Me ma_channel_converter_process_pcm_frames__mono_in(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
M6 iFrame;
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pFramesOut !=NULL);
MA_ASSERT(pFramesIn !=NULL);
MA_ASSERT(pConverter->channelsIn==1);
switch (pConverter->format)
{
case ma_format_u8:
{ ma_uint8*pFramesOutU8=( ma_uint8*)pFramesOut;
const ma_uint8*pFramesInU8=(const ma_uint8*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
M3 iChannel;
for (iChannel=0; iChannel<pConverter->channelsOut; iChannel+=1) {
 pFramesOutU8[iFrame*pConverter->channelsOut+iChannel]=pFramesInU8[iFrame];
}
}
} break;
case ma_format_s16:
{ ma_int16*pFramesOutS16=( ma_int16*)pFramesOut;
const ma_int16*pFramesInS16=(const ma_int16*)pFramesIn;
if (pConverter->channelsOut==2) {
for (iFrame=0; iFrame<frameCount;++iFrame) {
 pFramesOutS16[iFrame*2+0]=pFramesInS16[iFrame];
 pFramesOutS16[iFrame*2+1]=pFramesInS16[iFrame];
}
} else {
for (iFrame=0; iFrame<frameCount;++iFrame) {
 M3 iChannel;
 for (iChannel=0; iChannel<pConverter->channelsOut; iChannel+=1) {
 pFramesOutS16[iFrame*pConverter->channelsOut+iChannel]=pFramesInS16[iFrame];
 }
}
}
} break;
case ma_format_s24:
{ ma_uint8*pFramesOutS24=( ma_uint8*)pFramesOut;
const ma_uint8*pFramesInS24=(const ma_uint8*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
M3 iChannel;
for (iChannel=0; iChannel<pConverter->channelsOut; iChannel+=1) {
 M6 iSampleOut=iFrame*pConverter->channelsOut+iChannel;
 M6 iSampleIn=iFrame;
 pFramesOutS24[iSampleOut*3+0]=pFramesInS24[iSampleIn*3+0];
 pFramesOutS24[iSampleOut*3+1]=pFramesInS24[iSampleIn*3+1];
 pFramesOutS24[iSampleOut*3+2]=pFramesInS24[iSampleIn*3+2];
}
}
} break;
case ma_format_s32:
{ ma_int32*pFramesOutS32=( ma_int32*)pFramesOut;
const ma_int32*pFramesInS32=(const ma_int32*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
M3 iChannel;
for (iChannel=0; iChannel<pConverter->channelsOut; iChannel+=1) {
 pFramesOutS32[iFrame*pConverter->channelsOut+iChannel]=pFramesInS32[iFrame];
}
}
} break;
case ma_format_f32:
{ float*pFramesOutF32=( float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
if (pConverter->channelsOut==2) {
for (iFrame=0; iFrame<frameCount;++iFrame) {
 pFramesOutF32[iFrame*2+0]=pFramesInF32[iFrame];
 pFramesOutF32[iFrame*2+1]=pFramesInF32[iFrame];
}
} else {
for (iFrame=0; iFrame<frameCount;++iFrame) {
 M3 iChannel;
 for (iChannel=0; iChannel<pConverter->channelsOut; iChannel+=1) {
 pFramesOutF32[iFrame*pConverter->channelsOut+iChannel]=pFramesInF32[iFrame];
 }
}
}
} break;
default:Mr MA_INVALID_OPERATION;
}
Mr Ms;
}
static Me ma_channel_converter_process_pcm_frames__mono_out(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
M6 iFrame;
M3 iChannel;
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pFramesOut !=NULL);
MA_ASSERT(pFramesIn !=NULL);
MA_ASSERT(pConverter->channelsOut==1);
switch (pConverter->format)
{
case ma_format_u8:
{ ma_uint8*pFramesOutU8=( ma_uint8*)pFramesOut;
const ma_uint8*pFramesInU8=(const ma_uint8*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
ma_int32 t=0;
for (iChannel=0; iChannel<pConverter->channelsIn; iChannel+=1) {
 t+=ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*pConverter->channelsIn+iChannel]);
}
pFramesOutU8[iFrame]=ma_clip_u8(t / pConverter->channelsOut);
}
} break;
case ma_format_s16:
{ ma_int16*pFramesOutS16=( ma_int16*)pFramesOut;
const ma_int16*pFramesInS16=(const ma_int16*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
ma_int32 t=0;
for (iChannel=0; iChannel<pConverter->channelsIn; iChannel+=1) {
 t+=pFramesInS16[iFrame*pConverter->channelsIn+iChannel];
}
pFramesOutS16[iFrame]=(ma_int16)(t / pConverter->channelsIn);
}
} break;
case ma_format_s24:
{ ma_uint8*pFramesOutS24=( ma_uint8*)pFramesOut;
const ma_uint8*pFramesInS24=(const ma_uint8*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
ma_int64 t=0;
for (iChannel=0; iChannel<pConverter->channelsIn; iChannel+=1) {
 t+=ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*pConverter->channelsIn+iChannel)*3]);
}
ma_pcm_sample_s32_to_s24_no_scale(t / pConverter->channelsIn,&pFramesOutS24[iFrame*3]);
}
} break;
case ma_format_s32:
{ ma_int32*pFramesOutS32=( ma_int32*)pFramesOut;
const ma_int32*pFramesInS32=(const ma_int32*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
ma_int64 t=0;
for (iChannel=0; iChannel<pConverter->channelsIn; iChannel+=1) {
 t+=pFramesInS32[iFrame*pConverter->channelsIn+iChannel];
}
pFramesOutS32[iFrame]=(ma_int32)(t / pConverter->channelsIn);
}
} break;
case ma_format_f32:
{ float*pFramesOutF32=( float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
for (iFrame=0; iFrame<frameCount;++iFrame) {
float t=0;
for (iChannel=0; iChannel<pConverter->channelsIn; iChannel+=1) {
 t+=pFramesInF32[iFrame*pConverter->channelsIn+iChannel];
}
pFramesOutF32[iFrame]=t / pConverter->channelsIn;
}
} break;
default:Mr MA_INVALID_OPERATION;
}
Mr Ms;
}
static Me ma_channel_converter_process_pcm_frames__weights(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
M3 iFrame;
M3 iChannelIn;
M3 iChannelOut;
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pFramesOut !=NULL);
MA_ASSERT(pFramesIn !=NULL);
ma_zero_memory_64(pFramesOut,frameCount*ma_get_bytes_per_frame(pConverter->format,pConverter->channelsOut));
switch (pConverter->format)
{
case ma_format_u8:
{ ma_uint8*pFramesOutU8=( ma_uint8*)pFramesOut;
const ma_uint8*pFramesInU8=(const ma_uint8*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 ma_int16 u8_O=ma_pcm_sample_u8_to_s16_no_scale(pFramesOutU8[iFrame*pConverter->channelsOut+iChannelOut]);
 ma_int16 u8_I=ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8 [iFrame*pConverter->channelsIn+iChannelIn ]);
 ma_int32 s=(ma_int32)ma_clamp(u8_O+((u8_I*pConverter->weights.s16[iChannelIn][iChannelOut])>>MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT),-128,127);
 pFramesOutU8[iFrame*pConverter->channelsOut+iChannelOut]=ma_clip_u8((ma_int16)s);
 }
}
}
} break;
case ma_format_s16:
{ ma_int16*pFramesOutS16=( ma_int16*)pFramesOut;
const ma_int16*pFramesInS16=(const ma_int16*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 ma_int32 s=pFramesOutS16[iFrame*pConverter->channelsOut+iChannelOut];
 s+=(pFramesInS16[iFrame*pConverter->channelsIn+iChannelIn]*pConverter->weights.s16[iChannelIn][iChannelOut])>>MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
 pFramesOutS16[iFrame*pConverter->channelsOut+iChannelOut]=(ma_int16)ma_clamp(s,-32768,32767);
 }
}
}
} break;
case ma_format_s24:
{ ma_uint8*pFramesOutS24=( ma_uint8*)pFramesOut;
const ma_uint8*pFramesInS24=(const ma_uint8*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 ma_int64 s24_O=ma_pcm_sample_s24_to_s32_no_scale(&pFramesOutS24[(iFrame*pConverter->channelsOut+iChannelOut)*3]);
 ma_int64 s24_I=ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24 [(iFrame*pConverter->channelsIn+iChannelIn )*3]);
 ma_int64 s24=(ma_int32)ma_clamp(s24_O+((s24_I*pConverter->weights.s16[iChannelIn][iChannelOut])>>MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT),-8388608,8388607);
 ma_pcm_sample_s32_to_s24_no_scale(s24,&pFramesOutS24[(iFrame*pConverter->channelsOut+iChannelOut)*3]);
 }
}
}
} break;
case ma_format_s32:
{ ma_int32*pFramesOutS32=( ma_int32*)pFramesOut;
const ma_int32*pFramesInS32=(const ma_int32*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 ma_int64 s=pFramesOutS32[iFrame*pConverter->channelsOut+iChannelOut];
 s+=((ma_int64)pFramesInS32[iFrame*pConverter->channelsIn+iChannelIn]*pConverter->weights.s16[iChannelIn][iChannelOut])>>MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
 pFramesOutS32[iFrame*pConverter->channelsOut+iChannelOut]=ma_clip_s32(s);
 }
}
}
} break;
case ma_format_f32:
{ float*pFramesOutF32=( float*)pFramesOut;
const float*pFramesInF32=(const float*)pFramesIn;
for (iFrame=0; iFrame<frameCount; iFrame+=1) {
for (iChannelIn=0; iChannelIn<pConverter->channelsIn;++iChannelIn) {
 for (iChannelOut=0; iChannelOut<pConverter->channelsOut;++iChannelOut) {
 pFramesOutF32[iFrame*pConverter->channelsOut+iChannelOut]+=pFramesInF32[iFrame*pConverter->channelsIn+iChannelIn]*pConverter->weights.f32[iChannelIn][iChannelOut];
 }
}
}
} break;
default:Mr MA_INVALID_OPERATION;
}
Mr Ms;
}
MA_API Me ma_channel_converter_process_pcm_frames(ma_channel_converter*pConverter,Mv*pFramesOut,const Mv*pFramesIn,M6 frameCount)
{
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFramesOut==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFramesIn==NULL) {
ma_zero_memory_64(pFramesOut,frameCount*ma_get_bytes_per_frame(pConverter->format,pConverter->channelsOut));
Mr Ms;
}
switch (pConverter->conversionPath)
{
case ma_channel_conversion_path_passthrough:Mr ma_channel_converter_process_pcm_frames__passthrough(pConverter,pFramesOut,pFramesIn,frameCount);
case ma_channel_conversion_path_mono_out:Mr ma_channel_converter_process_pcm_frames__mono_out(pConverter,pFramesOut,pFramesIn,frameCount);
case ma_channel_conversion_path_mono_in:Mr ma_channel_converter_process_pcm_frames__mono_in(pConverter,pFramesOut,pFramesIn,frameCount);
case ma_channel_conversion_path_shuffle:Mr ma_channel_converter_process_pcm_frames__shuffle(pConverter,pFramesOut,pFramesIn,frameCount);
case ma_channel_conversion_path_weights:
default:
{
Mr ma_channel_converter_process_pcm_frames__weights(pConverter,pFramesOut,pFramesIn,frameCount);
}
}
}
MA_API Me ma_channel_converter_get_input_channel_map(const ma_channel_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap)
{
if (pConverter==NULL||pChannelMap==NULL) {
Mr MA_INVALID_ARGS;
}
ma_channel_map_copy_or_default(pChannelMap,channelMapCap,pConverter->pChannelMapIn,pConverter->channelsIn);
Mr Ms;
}
MA_API Me ma_channel_converter_get_output_channel_map(const ma_channel_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap)
{
if (pConverter==NULL||pChannelMap==NULL) {
Mr MA_INVALID_ARGS;
}
ma_channel_map_copy_or_default(pChannelMap,channelMapCap,pConverter->pChannelMapOut,pConverter->channelsOut);
Mr Ms;
}
MA_API ma_data_converter_config ma_data_converter_config_init_default(Mv)
{
ma_data_converter_config config;
MA_ZERO_OBJECT(&config);
config.ditherMode=ma_dither_mode_none;
config.resampling.algorithm=ma_resample_algorithm_linear;
config.allowDynamicSampleRate=MA_FALSE;
config.resampling.linear.lpfOrder=1;
Mr config;
}
MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn,ma_format formatOut,M3 channelsIn,M3 channelsOut,M3 sampleRateIn,M3 sampleRateOut)
{
ma_data_converter_config config=ma_data_converter_config_init_default();
config.formatIn=formatIn;
config.formatOut=formatOut;
config.channelsIn=channelsIn;
config.channelsOut=channelsOut;
config.sampleRateIn=sampleRateIn;
config.sampleRateOut=sampleRateOut;
Mr config;
}
typedef struct
{
size_t sizeInBytes;
size_t channelConverterOffset;
size_t resamplerOffset;
} ma_data_converter_heap_layout;
static ma_bool32 ma_data_converter_config_is_resampler_required(const ma_data_converter_config*Mo)
{
MA_ASSERT(Mo !=NULL);
Mr Mo->allowDynamicSampleRate||Mo->sampleRateIn !=Mo->sampleRateOut;
}
static ma_format ma_data_converter_config_get_mid_format(const ma_data_converter_config*Mo)
{
MA_ASSERT(Mo !=NULL);
if (ma_data_converter_config_is_resampler_required(Mo)&&Mo->resampling.algorithm !=ma_resample_algorithm_linear) {
Mr ma_format_f32;
} else { if (Mo->formatOut==ma_format_s16||Mo->formatOut==ma_format_f32) {
Mr Mo->formatOut;
} else if (Mo->formatIn==ma_format_s16||Mo->formatIn==ma_format_f32) {
Mr Mo->formatIn;
} else {
Mr ma_format_f32;
}
}
}
static ma_channel_converter_config ma_channel_converter_config_init_from_data_converter_config(const ma_data_converter_config*Mo)
{
ma_channel_converter_config channelConverterConfig;
MA_ASSERT(Mo !=NULL);
channelConverterConfig=ma_channel_converter_config_init(ma_data_converter_config_get_mid_format(Mo),Mo->channelsIn,Mo->pChannelMapIn,Mo->channelsOut,Mo->pChannelMapOut,Mo->channelMixMode);
channelConverterConfig.ppWeights=Mo->ppChannelWeights;
channelConverterConfig.calculateLFEFromSpatialChannels=Mo->calculateLFEFromSpatialChannels;
Mr channelConverterConfig;
}
static ma_resampler_config ma_resampler_config_init_from_data_converter_config(const ma_data_converter_config*Mo)
{
ma_resampler_config resamplerConfig;
M3 resamplerChannels;
MA_ASSERT(Mo !=NULL);
if (Mo->channelsIn<Mo->channelsOut) {
resamplerChannels=Mo->channelsIn;
} else {
resamplerChannels=Mo->channelsOut;
}
resamplerConfig=ma_resampler_config_init(ma_data_converter_config_get_mid_format(Mo),resamplerChannels,Mo->sampleRateIn,Mo->sampleRateOut,Mo->resampling.algorithm);
resamplerConfig.linear=Mo->resampling.linear;
resamplerConfig.pBackendVTable=Mo->resampling.pBackendVTable;
resamplerConfig.pBackendUserData=Mo->resampling.pBackendUserData;
Mr resamplerConfig;
}
static Me ma_data_converter_get_heap_layout(const ma_data_converter_config*Mo,ma_data_converter_heap_layout*pHeapLayout)
{
Me Mf;
MA_ASSERT(pHeapLayout !=NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->channelsIn==0||Mo->channelsOut==0) {
Mr MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes=0;
pHeapLayout->channelConverterOffset=pHeapLayout->sizeInBytes;
{
size_t heapSizeInBytes;
ma_channel_converter_config channelConverterConfig=ma_channel_converter_config_init_from_data_converter_config(Mo);
Mf=ma_channel_converter_get_heap_size(&channelConverterConfig,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=heapSizeInBytes;
}
pHeapLayout->resamplerOffset=pHeapLayout->sizeInBytes;
if (ma_data_converter_config_is_resampler_required(Mo)) {
size_t heapSizeInBytes;
ma_resampler_config resamplerConfig=ma_resampler_config_init_from_data_converter_config(Mo);
Mf=ma_resampler_get_heap_size(&resamplerConfig,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
pHeapLayout->sizeInBytes+=heapSizeInBytes;
}
pHeapLayout->sizeInBytes=ma_align_64(pHeapLayout->sizeInBytes);
Mr Ms;
}
MA_API Me ma_data_converter_get_heap_size(const ma_data_converter_config*Mo,size_t*pHeapSizeInBytes)
{
Me Mf;
ma_data_converter_heap_layout heapLayout;
if (pHeapSizeInBytes==NULL) {
Mr MA_INVALID_ARGS;
}
*pHeapSizeInBytes=0;
Mf=ma_data_converter_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
*pHeapSizeInBytes=heapLayout.sizeInBytes;
Mr Ms;
}
MA_API Me ma_data_converter_init_preallocated(const ma_data_converter_config*Mo,Mv*pHeap,ma_data_converter*pConverter)
{
Me Mf;
ma_data_converter_heap_layout heapLayout;
ma_format midFormat;
ma_bool32 isResamplingRequired;
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pConverter);
Mf=ma_data_converter_get_heap_layout(Mo,&heapLayout);
if (Mf !=Ms) {
Mr Mf;
}
pConverter->_pHeap=pHeap;
MA_ZERO_MEMORY(pHeap,heapLayout.sizeInBytes);
pConverter->formatIn=Mo->formatIn;
pConverter->formatOut=Mo->formatOut;
pConverter->channelsIn=Mo->channelsIn;
pConverter->channelsOut=Mo->channelsOut;
pConverter->sampleRateIn=Mo->sampleRateIn;
pConverter->sampleRateOut=Mo->sampleRateOut;
pConverter->ditherMode=Mo->ditherMode;
isResamplingRequired=ma_data_converter_config_is_resampler_required(Mo);
midFormat=ma_data_converter_config_get_mid_format(Mo);
{
ma_channel_converter_config channelConverterConfig=ma_channel_converter_config_init_from_data_converter_config(Mo);
Mf=ma_channel_converter_init_preallocated(&channelConverterConfig,ma_offset_ptr(pHeap,heapLayout.channelConverterOffset),&pConverter->channelConverter);
if (Mf !=Ms) {
Mr Mf;
}
if (pConverter->channelConverter.conversionPath !=ma_channel_conversion_path_passthrough) {
pConverter->hasChannelConverter=MA_TRUE;
}
}
if (isResamplingRequired) {
ma_resampler_config resamplerConfig=ma_resampler_config_init_from_data_converter_config(Mo);
Mf=ma_resampler_init_preallocated(&resamplerConfig,ma_offset_ptr(pHeap,heapLayout.resamplerOffset),&pConverter->resampler);
if (Mf !=Ms) {
Mr Mf;
}
pConverter->hasResampler=MA_TRUE;
}
if (pConverter->hasChannelConverter==MA_FALSE&&pConverter->hasResampler==MA_FALSE) {
if (pConverter->formatIn==pConverter->formatOut) {
pConverter->hasPreFormatConversion=MA_FALSE;
pConverter->hasPostFormatConversion=MA_FALSE;
} else {
pConverter->hasPreFormatConversion=MA_FALSE;
pConverter->hasPostFormatConversion=MA_TRUE;
}
} else {
if (pConverter->formatIn !=midFormat) {
pConverter->hasPreFormatConversion=MA_TRUE;
}
if (pConverter->formatOut !=midFormat) {
pConverter->hasPostFormatConversion=MA_TRUE;
}
}
if (pConverter->hasPreFormatConversion==MA_FALSE&&
pConverter->hasPostFormatConversion==MA_FALSE&&
pConverter->hasChannelConverter==MA_FALSE&&
pConverter->hasResampler==MA_FALSE) {
pConverter->isPassthrough=MA_TRUE;
}
if (pConverter->isPassthrough) {
pConverter->executionPath=ma_data_converter_execution_path_passthrough;
} else {
if (pConverter->channelsIn<pConverter->channelsOut) {
MA_ASSERT(pConverter->hasChannelConverter==MA_TRUE);
if (pConverter->hasResampler) {
pConverter->executionPath=ma_data_converter_execution_path_resample_first;
} else {
pConverter->executionPath=ma_data_converter_execution_path_channels_only;
}
} else {
if (pConverter->hasChannelConverter) {
if (pConverter->hasResampler) {
 pConverter->executionPath=ma_data_converter_execution_path_channels_first;
} else {
 pConverter->executionPath=ma_data_converter_execution_path_channels_only;
}
} else {
if (pConverter->hasResampler) {
 pConverter->executionPath=ma_data_converter_execution_path_resample_only;
} else {
 pConverter->executionPath=ma_data_converter_execution_path_format_only;
}
}
}
}
Mr Ms;
}
MA_API Me ma_data_converter_init(const ma_data_converter_config*Mo,const ma_allocation_callbacks*pAllocationCallbacks,ma_data_converter*pConverter)
{
Me Mf;
size_t heapSizeInBytes;
Mv*pHeap;
Mf=ma_data_converter_get_heap_size(Mo,&heapSizeInBytes);
if (Mf !=Ms) {
Mr Mf;
}
if (heapSizeInBytes>0) {
pHeap=ma_malloc(heapSizeInBytes,pAllocationCallbacks);
if (pHeap==NULL) {
Mr MA_OUT_OF_MEMORY;
}
} else {
pHeap=NULL;
}
Mf=ma_data_converter_init_preallocated(Mo,pHeap,pConverter);
if (Mf !=Ms) {
ma_free(pHeap,pAllocationCallbacks);
Mr Mf;
}
pConverter->_ownsHeap=MA_TRUE;
Mr Ms;
}
MA_API Mv ma_data_converter_uninit(ma_data_converter*pConverter,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pConverter==NULL) {
Mr;
}
if (pConverter->hasResampler) {
ma_resampler_uninit(&pConverter->resampler,pAllocationCallbacks);
}
ma_channel_converter_uninit(&pConverter->channelConverter,pAllocationCallbacks);
if (pConverter->_ownsHeap) {
ma_free(pConverter->_pHeap,pAllocationCallbacks);
}
}
static Me ma_data_converter_process_pcm_frames__passthrough(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
M6 frameCountIn;
M6 frameCountOut;
M6 frameCount;
MA_ASSERT(pConverter !=NULL);
frameCountIn=0;
if (pFrameCountIn !=NULL) {
frameCountIn=*pFrameCountIn;
}
frameCountOut=0;
if (pFrameCountOut !=NULL) {
frameCountOut=*pFrameCountOut;
}
frameCount=ma_min(frameCountIn,frameCountOut);
if (pFramesOut !=NULL) {
if (pFramesIn !=NULL) {
ma_copy_memory_64(pFramesOut,pFramesIn,frameCount*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
} else {
ma_zero_memory_64(pFramesOut,frameCount*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
}
}
if (pFrameCountIn !=NULL) {
*pFrameCountIn=frameCount;
}
if (pFrameCountOut !=NULL) {
*pFrameCountOut=frameCount;
}
Mr Ms;
}
static Me ma_data_converter_process_pcm_frames__format_only(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
M6 frameCountIn;
M6 frameCountOut;
M6 frameCount;
MA_ASSERT(pConverter !=NULL);
frameCountIn=0;
if (pFrameCountIn !=NULL) {
frameCountIn=*pFrameCountIn;
}
frameCountOut=0;
if (pFrameCountOut !=NULL) {
frameCountOut=*pFrameCountOut;
}
frameCount=ma_min(frameCountIn,frameCountOut);
if (pFramesOut !=NULL) {
if (pFramesIn !=NULL) {
ma_convert_pcm_frames_format(pFramesOut,pConverter->formatOut,pFramesIn,pConverter->formatIn,frameCount,pConverter->channelsIn,pConverter->ditherMode);
} else {
ma_zero_memory_64(pFramesOut,frameCount*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
}
}
if (pFrameCountIn !=NULL) {
*pFrameCountIn=frameCount;
}
if (pFrameCountOut !=NULL) {
*pFrameCountOut=frameCount;
}
Mr Ms;
}
static Me ma_data_converter_process_pcm_frames__resample_with_format_conversion(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
Me Mf=Ms;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
MA_ASSERT(pConverter !=NULL);
frameCountIn=0;
if (pFrameCountIn !=NULL) {
frameCountIn=*pFrameCountIn;
}
frameCountOut=0;
if (pFrameCountOut !=NULL) {
frameCountOut=*pFrameCountOut;
}
framesProcessedIn=0;
framesProcessedOut=0;
while (framesProcessedOut<frameCountOut) {
ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
const M3 tempBufferOutCap=sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format,pConverter->resampler.Mh);
const Mv*pFramesInThisIteration; Mv*pFramesOutThisIteration;
M6 frameCountInThisIteration;
M6 frameCountOutThisIteration;
if (pFramesIn !=NULL) {
pFramesInThisIteration=ma_offset_ptr(pFramesIn,framesProcessedIn*ma_get_bytes_per_frame(pConverter->formatIn,pConverter->channelsIn));
} else {
pFramesInThisIteration=NULL;
}
if (pFramesOut !=NULL) {
pFramesOutThisIteration=ma_offset_ptr(pFramesOut,framesProcessedOut*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
} else {
pFramesOutThisIteration=NULL;
}
if (pConverter->hasPreFormatConversion) {
ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
const M3 tempBufferInCap=sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format,pConverter->resampler.Mh);
frameCountInThisIteration=(frameCountIn-framesProcessedIn);
if (frameCountInThisIteration>tempBufferInCap) {
frameCountInThisIteration=tempBufferInCap;
}
if (pConverter->hasPostFormatConversion) {
if (frameCountInThisIteration>tempBufferOutCap) {
 frameCountInThisIteration=tempBufferOutCap;
}
}
if (pFramesInThisIteration !=NULL) {
ma_convert_pcm_frames_format(pTempBufferIn,pConverter->resampler.format,pFramesInThisIteration,pConverter->formatIn,frameCountInThisIteration,pConverter->channelsIn,pConverter->ditherMode);
} else {
MA_ZERO_MEMORY(pTempBufferIn,sizeof(pTempBufferIn));
}
frameCountOutThisIteration=(frameCountOut-framesProcessedOut);
if (pConverter->hasPostFormatConversion) {
if (frameCountOutThisIteration>tempBufferOutCap) {
 frameCountOutThisIteration=tempBufferOutCap;
}
Mf=ma_resampler_process_pcm_frames(&pConverter->resampler,pTempBufferIn,&frameCountInThisIteration,pTempBufferOut,&frameCountOutThisIteration);
} else {
Mf=ma_resampler_process_pcm_frames(&pConverter->resampler,pTempBufferIn,&frameCountInThisIteration,pFramesOutThisIteration,&frameCountOutThisIteration);
}
if (Mf !=Ms) {
break;
}
} else {
MA_ASSERT(pConverter->hasPostFormatConversion==MA_TRUE);
frameCountInThisIteration=(frameCountIn-framesProcessedIn);
frameCountOutThisIteration=(frameCountOut-framesProcessedOut);
if (frameCountOutThisIteration>tempBufferOutCap) {
frameCountOutThisIteration=tempBufferOutCap;
}
Mf=ma_resampler_process_pcm_frames(&pConverter->resampler,pFramesInThisIteration,&frameCountInThisIteration,pTempBufferOut,&frameCountOutThisIteration);
if (Mf !=Ms) {
break;
}
}
if (pConverter->hasPostFormatConversion) {
if (pFramesOutThisIteration !=NULL) {
ma_convert_pcm_frames_format(pFramesOutThisIteration,pConverter->formatOut,pTempBufferOut,pConverter->resampler.format,frameCountOutThisIteration,pConverter->resampler.Mh,pConverter->ditherMode);
}
}
framesProcessedIn+=frameCountInThisIteration;
framesProcessedOut+=frameCountOutThisIteration;
MA_ASSERT(framesProcessedIn<=frameCountIn);
MA_ASSERT(framesProcessedOut<=frameCountOut);
if (frameCountOutThisIteration==0) {
break;
}
}
if (pFrameCountIn !=NULL) {
*pFrameCountIn=framesProcessedIn;
}
if (pFrameCountOut !=NULL) {
*pFrameCountOut=framesProcessedOut;
}
Mr Mf;
}
static Me ma_data_converter_process_pcm_frames__resample_only(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
MA_ASSERT(pConverter !=NULL);
if (pConverter->hasPreFormatConversion==MA_FALSE&&pConverter->hasPostFormatConversion==MA_FALSE) {
Mr ma_resampler_process_pcm_frames(&pConverter->resampler,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
} else {
Mr ma_data_converter_process_pcm_frames__resample_with_format_conversion(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
}
}
static Me ma_data_converter_process_pcm_frames__channels_only(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
Me Mf;
M6 frameCountIn;
M6 frameCountOut;
M6 frameCount;
MA_ASSERT(pConverter !=NULL);
frameCountIn=0;
if (pFrameCountIn !=NULL) {
frameCountIn=*pFrameCountIn;
}
frameCountOut=0;
if (pFrameCountOut !=NULL) {
frameCountOut=*pFrameCountOut;
}
frameCount=ma_min(frameCountIn,frameCountOut);
if (pConverter->hasPreFormatConversion==MA_FALSE&&pConverter->hasPostFormatConversion==MA_FALSE) {
Mf=ma_channel_converter_process_pcm_frames(&pConverter->channelConverter,pFramesOut,pFramesIn,frameCount);
if (Mf !=Ms) {
Mr Mf;
}
} else {
M6 framesProcessed=0;
while (framesProcessed<frameCount) {
ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
const M3 tempBufferOutCap=sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format,pConverter->channelConverter.channelsOut);
const Mv*pFramesInThisIteration; Mv*pFramesOutThisIteration;
M6 frameCountThisIteration;
if (pFramesIn !=NULL) {
pFramesInThisIteration=ma_offset_ptr(pFramesIn,framesProcessed*ma_get_bytes_per_frame(pConverter->formatIn,pConverter->channelsIn));
} else {
pFramesInThisIteration=NULL;
}
if (pFramesOut !=NULL) {
pFramesOutThisIteration=ma_offset_ptr(pFramesOut,framesProcessed*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
} else {
pFramesOutThisIteration=NULL;
}
if (pConverter->hasPreFormatConversion) {
ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
const M3 tempBufferInCap=sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format,pConverter->channelConverter.channelsIn);
frameCountThisIteration=(frameCount-framesProcessed);
if (frameCountThisIteration>tempBufferInCap) {
 frameCountThisIteration=tempBufferInCap;
}
if (pConverter->hasPostFormatConversion) {
 if (frameCountThisIteration>tempBufferOutCap) {
 frameCountThisIteration=tempBufferOutCap;
 }
}
if (pFramesInThisIteration !=NULL) {
 ma_convert_pcm_frames_format(pTempBufferIn,pConverter->channelConverter.format,pFramesInThisIteration,pConverter->formatIn,frameCountThisIteration,pConverter->channelsIn,pConverter->ditherMode);
} else {
 MA_ZERO_MEMORY(pTempBufferIn,sizeof(pTempBufferIn));
}
if (pConverter->hasPostFormatConversion) {
 Mf=ma_channel_converter_process_pcm_frames(&pConverter->channelConverter,pTempBufferOut,pTempBufferIn,frameCountThisIteration);
} else {
 Mf=ma_channel_converter_process_pcm_frames(&pConverter->channelConverter,pFramesOutThisIteration,pTempBufferIn,frameCountThisIteration);
}
if (Mf !=Ms) {
 break;
}
} else {
MA_ASSERT(pConverter->hasPostFormatConversion==MA_TRUE);
frameCountThisIteration=(frameCount-framesProcessed);
if (frameCountThisIteration>tempBufferOutCap) {
 frameCountThisIteration=tempBufferOutCap;
}
Mf=ma_channel_converter_process_pcm_frames(&pConverter->channelConverter,pTempBufferOut,pFramesInThisIteration,frameCountThisIteration);
if (Mf !=Ms) {
 break;
}
}
if (pConverter->hasPostFormatConversion) {
if (pFramesOutThisIteration !=NULL) {
 ma_convert_pcm_frames_format(pFramesOutThisIteration,pConverter->formatOut,pTempBufferOut,pConverter->channelConverter.format,frameCountThisIteration,pConverter->channelConverter.channelsOut,pConverter->ditherMode);
}
}
framesProcessed+=frameCountThisIteration;
}
}
if (pFrameCountIn !=NULL) {
*pFrameCountIn=frameCount;
}
if (pFrameCountOut !=NULL) {
*pFrameCountOut=frameCount;
}
Mr Ms;
}
static Me ma_data_converter_process_pcm_frames__resample_first(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
Me Mf;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 tempBufferInCap;
ma_uint8 pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 tempBufferMidCap;
ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 tempBufferOutCap;
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pConverter->resampler.format==pConverter->channelConverter.format);
MA_ASSERT(pConverter->resampler.Mh==pConverter->channelConverter.channelsIn);
MA_ASSERT(pConverter->resampler.Mh<pConverter->channelConverter.channelsOut);
frameCountIn=0;
if (pFrameCountIn !=NULL) {
frameCountIn=*pFrameCountIn;
}
frameCountOut=0;
if (pFrameCountOut !=NULL) {
frameCountOut=*pFrameCountOut;
}
framesProcessedIn=0;
framesProcessedOut=0;
tempBufferInCap=sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format,pConverter->resampler.Mh);
tempBufferMidCap=sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format,pConverter->resampler.Mh);
tempBufferOutCap=sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format,pConverter->channelConverter.channelsOut);
while (framesProcessedOut<frameCountOut) {
M6 frameCountInThisIteration;
M6 frameCountOutThisIteration;
const Mv*pRunningFramesIn=NULL;
Mv*pRunningFramesOut=NULL;
const Mv*pResampleBufferIn;
Mv*pChannelsBufferOut;
if (pFramesIn !=NULL) {
pRunningFramesIn=ma_offset_ptr(pFramesIn,framesProcessedIn*ma_get_bytes_per_frame(pConverter->formatIn,pConverter->channelsIn));
}
if (pFramesOut !=NULL) {
pRunningFramesOut=ma_offset_ptr(pFramesOut,framesProcessedOut*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
}
frameCountInThisIteration=(frameCountIn-framesProcessedIn);
if (pConverter->hasPreFormatConversion) {
if (frameCountInThisIteration>tempBufferInCap) {
frameCountInThisIteration=tempBufferInCap;
}
}
frameCountOutThisIteration=(frameCountOut-framesProcessedOut);
if (frameCountOutThisIteration>tempBufferMidCap) {
frameCountOutThisIteration=tempBufferMidCap;
}
if (pConverter->hasPostFormatConversion) {
if (frameCountOutThisIteration>tempBufferOutCap) {
frameCountOutThisIteration=tempBufferOutCap;
}
}
#if 1
{
M6 requiredInputFrameCount;
Mf=ma_resampler_get_required_input_frame_count(&pConverter->resampler,frameCountOutThisIteration,&requiredInputFrameCount);
if (Mf !=Ms) {
requiredInputFrameCount=(frameCountOutThisIteration*pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut;
}
if (frameCountInThisIteration>requiredInputFrameCount) {
frameCountInThisIteration=requiredInputFrameCount;
}
}
#endif
if (pConverter->hasPreFormatConversion) {
if (pFramesIn !=NULL) {
ma_convert_pcm_frames_format(pTempBufferIn,pConverter->resampler.format,pRunningFramesIn,pConverter->formatIn,frameCountInThisIteration,pConverter->channelsIn,pConverter->ditherMode);
pResampleBufferIn=pTempBufferIn;
} else {
pResampleBufferIn=NULL;
}
} else {
pResampleBufferIn=pRunningFramesIn;
}
Mf=ma_resampler_process_pcm_frames(&pConverter->resampler,pResampleBufferIn,&frameCountInThisIteration,pTempBufferMid,&frameCountOutThisIteration);
if (Mf !=Ms) {
Mr Mf;
}
if (pFramesOut !=NULL) {
if (pConverter->hasPostFormatConversion) {
pChannelsBufferOut=pTempBufferOut;
} else {
pChannelsBufferOut=pRunningFramesOut;
}
Mf=ma_channel_converter_process_pcm_frames(&pConverter->channelConverter,pChannelsBufferOut,pTempBufferMid,frameCountOutThisIteration);
if (Mf !=Ms) {
Mr Mf;
}
if (pConverter->hasPostFormatConversion) {
ma_convert_pcm_frames_format(pRunningFramesOut,pConverter->formatOut,pChannelsBufferOut,pConverter->channelConverter.format,frameCountOutThisIteration,pConverter->channelConverter.channelsOut,pConverter->ditherMode);
}
}
framesProcessedIn+=frameCountInThisIteration;
framesProcessedOut+=frameCountOutThisIteration;
MA_ASSERT(framesProcessedIn<=frameCountIn);
MA_ASSERT(framesProcessedOut<=frameCountOut);
if (frameCountOutThisIteration==0) {
break;
}
}
if (pFrameCountIn !=NULL) {
*pFrameCountIn=framesProcessedIn;
}
if (pFrameCountOut !=NULL) {
*pFrameCountOut=framesProcessedOut;
}
Mr Ms;
}
static Me ma_data_converter_process_pcm_frames__channels_first(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
Me Mf;
M6 frameCountIn;
M6 frameCountOut;
M6 framesProcessedIn;
M6 framesProcessedOut;
ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 tempBufferInCap;
ma_uint8 pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 tempBufferMidCap;
ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
M6 tempBufferOutCap;
MA_ASSERT(pConverter !=NULL);
MA_ASSERT(pConverter->resampler.format==pConverter->channelConverter.format);
MA_ASSERT(pConverter->resampler.Mh==pConverter->channelConverter.channelsOut);
MA_ASSERT(pConverter->resampler.Mh<=pConverter->channelConverter.channelsIn);
frameCountIn=0;
if (pFrameCountIn !=NULL) {
frameCountIn=*pFrameCountIn;
}
frameCountOut=0;
if (pFrameCountOut !=NULL) {
frameCountOut=*pFrameCountOut;
}
framesProcessedIn=0;
framesProcessedOut=0;
tempBufferInCap=sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format,pConverter->channelConverter.channelsIn);
tempBufferMidCap=sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format,pConverter->channelConverter.channelsOut);
tempBufferOutCap=sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format,pConverter->resampler.Mh);
while (framesProcessedOut<frameCountOut) {
M6 frameCountInThisIteration;
M6 frameCountOutThisIteration;
const Mv*pRunningFramesIn=NULL;
Mv*pRunningFramesOut=NULL;
const Mv*pChannelsBufferIn;
Mv*pResampleBufferOut;
if (pFramesIn !=NULL) {
pRunningFramesIn=ma_offset_ptr(pFramesIn,framesProcessedIn*ma_get_bytes_per_frame(pConverter->formatIn,pConverter->channelsIn));
}
if (pFramesOut !=NULL) {
pRunningFramesOut=ma_offset_ptr(pFramesOut,framesProcessedOut*ma_get_bytes_per_frame(pConverter->formatOut,pConverter->channelsOut));
}
frameCountOutThisIteration=(frameCountOut-framesProcessedOut);
if (frameCountOutThisIteration>tempBufferMidCap) {
frameCountOutThisIteration=tempBufferMidCap;
}
if (pConverter->hasPostFormatConversion) {
if (frameCountOutThisIteration>tempBufferOutCap) {
frameCountOutThisIteration=tempBufferOutCap;
}
}
frameCountInThisIteration=(frameCountIn-framesProcessedIn);
if (pConverter->hasPreFormatConversion) {
if (frameCountInThisIteration>tempBufferInCap) {
frameCountInThisIteration=tempBufferInCap;
}
}
if (frameCountInThisIteration>tempBufferMidCap) {
frameCountInThisIteration=tempBufferMidCap;
}
#if 1
{
M6 requiredInputFrameCount;
Mf=ma_resampler_get_required_input_frame_count(&pConverter->resampler,frameCountOutThisIteration,&requiredInputFrameCount);
if (Mf !=Ms) {
requiredInputFrameCount=(frameCountOutThisIteration*pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut;
}
if (frameCountInThisIteration>requiredInputFrameCount) {
frameCountInThisIteration=requiredInputFrameCount;
}
}
#endif
if (pConverter->hasPreFormatConversion) {
if (pRunningFramesIn !=NULL) {
ma_convert_pcm_frames_format(pTempBufferIn,pConverter->channelConverter.format,pRunningFramesIn,pConverter->formatIn,frameCountInThisIteration,pConverter->channelsIn,pConverter->ditherMode);
pChannelsBufferIn=pTempBufferIn;
} else {
pChannelsBufferIn=NULL;
}
} else {
pChannelsBufferIn=pRunningFramesIn;
}
Mf=ma_channel_converter_process_pcm_frames(&pConverter->channelConverter,pTempBufferMid,pChannelsBufferIn,frameCountInThisIteration);
if (Mf !=Ms) {
Mr Mf;
}
if (pConverter->hasPostFormatConversion) {
pResampleBufferOut=pTempBufferOut;
} else {
pResampleBufferOut=pRunningFramesOut;
}
Mf=ma_resampler_process_pcm_frames(&pConverter->resampler,pTempBufferMid,&frameCountInThisIteration,pResampleBufferOut,&frameCountOutThisIteration);
if (Mf !=Ms) {
Mr Mf;
}
if (pConverter->hasPostFormatConversion) {
if (pRunningFramesOut !=NULL) {
ma_convert_pcm_frames_format(pRunningFramesOut,pConverter->formatOut,pResampleBufferOut,pConverter->resampler.format,frameCountOutThisIteration,pConverter->channelsOut,pConverter->ditherMode);
}
}
framesProcessedIn+=frameCountInThisIteration;
framesProcessedOut+=frameCountOutThisIteration;
MA_ASSERT(framesProcessedIn<=frameCountIn);
MA_ASSERT(framesProcessedOut<=frameCountOut);
if (frameCountOutThisIteration==0) {
break;
}
}
if (pFrameCountIn !=NULL) {
*pFrameCountIn=framesProcessedIn;
}
if (pFrameCountOut !=NULL) {
*pFrameCountOut=framesProcessedOut;
}
Mr Ms;
}
MA_API Me ma_data_converter_process_pcm_frames(ma_data_converter*pConverter,const Mv*pFramesIn,M6*pFrameCountIn,Mv*pFramesOut,M6*pFrameCountOut)
{
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
switch (pConverter->executionPath)
{
case ma_data_converter_execution_path_passthrough:Mr ma_data_converter_process_pcm_frames__passthrough(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
case ma_data_converter_execution_path_format_only:Mr ma_data_converter_process_pcm_frames__format_only(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
case ma_data_converter_execution_path_channels_only:Mr ma_data_converter_process_pcm_frames__channels_only(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
case ma_data_converter_execution_path_resample_only:Mr ma_data_converter_process_pcm_frames__resample_only(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
case ma_data_converter_execution_path_resample_first:Mr ma_data_converter_process_pcm_frames__resample_first(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
case ma_data_converter_execution_path_channels_first:Mr ma_data_converter_process_pcm_frames__channels_first(pConverter,pFramesIn,pFrameCountIn,pFramesOut,pFrameCountOut);
default:Mr MA_INVALID_OPERATION;
}
}
MA_API Me ma_data_converter_set_rate(ma_data_converter*pConverter,M3 sampleRateIn,M3 sampleRateOut)
{
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasResampler==MA_FALSE) {
Mr MA_INVALID_OPERATION;
}
Mr ma_resampler_set_rate(&pConverter->resampler,sampleRateIn,sampleRateOut);
}
MA_API Me ma_data_converter_set_rate_ratio(ma_data_converter*pConverter,float ratioInOut)
{
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasResampler==MA_FALSE) {
Mr MA_INVALID_OPERATION;
}
Mr ma_resampler_set_rate_ratio(&pConverter->resampler,ratioInOut);
}
MA_API M6 ma_data_converter_get_input_latency(const ma_data_converter*pConverter)
{
if (pConverter==NULL) {
Mr 0;
}
if (pConverter->hasResampler) {
Mr ma_resampler_get_input_latency(&pConverter->resampler);
}
Mr 0;
}
MA_API M6 ma_data_converter_get_output_latency(const ma_data_converter*pConverter)
{
if (pConverter==NULL) {
Mr 0;
}
if (pConverter->hasResampler) {
Mr ma_resampler_get_output_latency(&pConverter->resampler);
}
Mr 0;
}
MA_API Me ma_data_converter_get_required_input_frame_count(const ma_data_converter*pConverter,M6 outputFrameCount,M6*pInputFrameCount)
{
if (pInputFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
*pInputFrameCount=0;
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasResampler) {
Mr ma_resampler_get_required_input_frame_count(&pConverter->resampler,outputFrameCount,pInputFrameCount);
} else {
*pInputFrameCount=outputFrameCount;
Mr Ms;
}
}
MA_API Me ma_data_converter_get_expected_output_frame_count(const ma_data_converter*pConverter,M6 inputFrameCount,M6*pOutputFrameCount)
{
if (pOutputFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
*pOutputFrameCount=0;
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasResampler) {
Mr ma_resampler_get_expected_output_frame_count(&pConverter->resampler,inputFrameCount,pOutputFrameCount);
} else {
*pOutputFrameCount=inputFrameCount;
Mr Ms;
}
}
MA_API Me ma_data_converter_get_input_channel_map(const ma_data_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap)
{
if (pConverter==NULL||pChannelMap==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasChannelConverter) {
ma_channel_converter_get_output_channel_map(&pConverter->channelConverter,pChannelMap,channelMapCap);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,pConverter->channelsOut);
}
Mr Ms;
}
MA_API Me ma_data_converter_get_output_channel_map(const ma_data_converter*pConverter,ma_channel*pChannelMap,size_t channelMapCap)
{
if (pConverter==NULL||pChannelMap==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasChannelConverter) {
ma_channel_converter_get_input_channel_map(&pConverter->channelConverter,pChannelMap,channelMapCap);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,pConverter->channelsIn);
}
Mr Ms;
}
MA_API Me ma_data_converter_reset(ma_data_converter*pConverter)
{
if (pConverter==NULL) {
Mr MA_INVALID_ARGS;
}
if (pConverter->hasResampler==MA_FALSE) {
Mr Ms;
}
Mr ma_resampler_reset(&pConverter->resampler);
}
static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap,M3 channelCount,M3 channelIndex);
MA_API ma_channel ma_channel_map_get_channel(const ma_channel*pChannelMap,M3 channelCount,M3 channelIndex)
{
if (pChannelMap==NULL) {
Mr ma_channel_map_init_standard_channel(ma_standard_channel_map_default,channelCount,channelIndex);
} else {
if (channelIndex>=channelCount) {
Mr MA_CHANNEL_NONE;
}
Mr pChannelMap[channelIndex];
}
}
MA_API Mv ma_channel_map_init_blank(ma_channel*pChannelMap,M3 Mh)
{
if (pChannelMap==NULL) {
Mr;
}
MA_ZERO_MEMORY(pChannelMap,sizeof(*pChannelMap)*Mh);
}
static ma_channel ma_channel_map_init_standard_channel_microsoft(M3 channelCount,M3 channelIndex)
{
if (channelCount==0||channelIndex>=channelCount) {
Mr MA_CHANNEL_NONE;
}
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 4:
{
switch (channelIndex) {
#ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_BACK_CENTER;
#else
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
#endif
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 6:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_LFE;
case 4:Mr MA_CHANNEL_SIDE_LEFT;
case 5:Mr MA_CHANNEL_SIDE_RIGHT;
}
} break;
case 7:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_LFE;
case 4:Mr MA_CHANNEL_BACK_CENTER;
case 5:Mr MA_CHANNEL_SIDE_LEFT;
case 6:Mr MA_CHANNEL_SIDE_RIGHT;
}
} break;
case 8:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_LFE;
case 4:Mr MA_CHANNEL_BACK_LEFT;
case 5:Mr MA_CHANNEL_BACK_RIGHT;
case 6:Mr MA_CHANNEL_SIDE_LEFT;
case 7:Mr MA_CHANNEL_SIDE_RIGHT;
}
} break;
}
if (channelCount>8) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-8));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel_alsa(M3 channelCount,M3 channelIndex)
{
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 4:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
case 4:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 6:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
case 4:Mr MA_CHANNEL_FRONT_CENTER;
case 5:Mr MA_CHANNEL_LFE;
}
} break;
case 7:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
case 4:Mr MA_CHANNEL_FRONT_CENTER;
case 5:Mr MA_CHANNEL_LFE;
case 6:Mr MA_CHANNEL_BACK_CENTER;
}
} break;
case 8:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
case 4:Mr MA_CHANNEL_FRONT_CENTER;
case 5:Mr MA_CHANNEL_LFE;
case 6:Mr MA_CHANNEL_SIDE_LEFT;
case 7:Mr MA_CHANNEL_SIDE_RIGHT;
}
} break;
}
if (channelCount>8) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-8));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel_rfc3551(M3 channelCount,M3 channelIndex)
{
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 4:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_BACK_CENTER;
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 6:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_SIDE_LEFT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_FRONT_RIGHT;
case 4:Mr MA_CHANNEL_SIDE_RIGHT;
case 5:Mr MA_CHANNEL_BACK_CENTER;
}
} break;
}
if (channelCount>6) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-6));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel_flac(M3 channelCount,M3 channelIndex)
{
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 4:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 6:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_LFE;
case 4:Mr MA_CHANNEL_BACK_LEFT;
case 5:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 7:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_LFE;
case 4:Mr MA_CHANNEL_BACK_CENTER;
case 5:Mr MA_CHANNEL_SIDE_LEFT;
case 6:Mr MA_CHANNEL_SIDE_RIGHT;
}
} break;
case 8:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_LFE;
case 4:Mr MA_CHANNEL_BACK_LEFT;
case 5:Mr MA_CHANNEL_BACK_RIGHT;
case 6:Mr MA_CHANNEL_SIDE_LEFT;
case 7:Mr MA_CHANNEL_SIDE_RIGHT;
}
} break;
}
if (channelCount>8) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-8));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel_vorbis(M3 channelCount,M3 channelIndex)
{
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 4:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 6:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
case 5:Mr MA_CHANNEL_LFE;
}
} break;
case 7:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_SIDE_LEFT;
case 4:Mr MA_CHANNEL_SIDE_RIGHT;
case 5:Mr MA_CHANNEL_BACK_CENTER;
case 6:Mr MA_CHANNEL_LFE;
}
} break;
case 8:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_SIDE_LEFT;
case 4:Mr MA_CHANNEL_SIDE_RIGHT;
case 5:Mr MA_CHANNEL_BACK_LEFT;
case 6:Mr MA_CHANNEL_BACK_RIGHT;
case 7:Mr MA_CHANNEL_LFE;
}
} break;
}
if (channelCount>8) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-8));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel_sound4(M3 channelCount,M3 channelIndex)
{
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 4:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 6:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_BACK_LEFT;
case 4:Mr MA_CHANNEL_BACK_RIGHT;
case 5:Mr MA_CHANNEL_LFE;
}
} break;
case 7:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_SIDE_LEFT;
case 4:Mr MA_CHANNEL_SIDE_RIGHT;
case 5:Mr MA_CHANNEL_BACK_CENTER;
case 6:Mr MA_CHANNEL_LFE;
}
} break;
case 8:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_CENTER;
case 2:Mr MA_CHANNEL_FRONT_RIGHT;
case 3:Mr MA_CHANNEL_SIDE_LEFT;
case 4:Mr MA_CHANNEL_SIDE_RIGHT;
case 5:Mr MA_CHANNEL_BACK_LEFT;
case 6:Mr MA_CHANNEL_BACK_RIGHT;
case 7:Mr MA_CHANNEL_LFE;
}
} break;
}
if (channelCount>8) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-8));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel_sndio(M3 channelCount,M3 channelIndex)
{
switch (channelCount)
{
case 0:Mr MA_CHANNEL_NONE;
case 1:
{
Mr MA_CHANNEL_MONO;
} break;
case 2:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
}
} break;
case 3:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 4:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
}
} break;
case 5:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
case 4:Mr MA_CHANNEL_FRONT_CENTER;
}
} break;
case 6:
default:
{
switch (channelIndex) {
case 0:Mr MA_CHANNEL_FRONT_LEFT;
case 1:Mr MA_CHANNEL_FRONT_RIGHT;
case 2:Mr MA_CHANNEL_BACK_LEFT;
case 3:Mr MA_CHANNEL_BACK_RIGHT;
case 4:Mr MA_CHANNEL_FRONT_CENTER;
case 5:Mr MA_CHANNEL_LFE;
}
} break;
}
if (channelCount>6) {
if (channelIndex<32) {
Mr (ma_channel)(MA_CHANNEL_AUX_0+(channelIndex-6));
}
}
Mr MA_CHANNEL_NONE;
}
static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap,M3 channelCount,M3 channelIndex)
{
if (channelCount==0||channelIndex>=channelCount) {
Mr MA_CHANNEL_NONE;
}
switch (standardChannelMap)
{
case ma_standard_channel_map_alsa:
{
Mr ma_channel_map_init_standard_channel_alsa(channelCount,channelIndex);
} break;
case ma_standard_channel_map_rfc3551:
{
Mr ma_channel_map_init_standard_channel_rfc3551(channelCount,channelIndex);
} break;
case ma_standard_channel_map_flac:
{
Mr ma_channel_map_init_standard_channel_flac(channelCount,channelIndex);
} break;
case ma_standard_channel_map_vorbis:
{
Mr ma_channel_map_init_standard_channel_vorbis(channelCount,channelIndex);
} break;
case ma_standard_channel_map_sound4:
{
Mr ma_channel_map_init_standard_channel_sound4(channelCount,channelIndex);
} break;
case ma_standard_channel_map_sndio:
{
Mr ma_channel_map_init_standard_channel_sndio(channelCount,channelIndex);
} break;
case ma_standard_channel_map_microsoft:
default:
{
Mr ma_channel_map_init_standard_channel_microsoft(channelCount,channelIndex);
} break;
}
}
MA_API Mv ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap,ma_channel*pChannelMap,size_t channelMapCap,M3 Mh)
{
M3 iChannel;
if (pChannelMap==NULL||channelMapCap==0||Mh==0) {
Mr;
}
for (iChannel=0; iChannel<Mh; iChannel+=1) {
if (channelMapCap==0) {
break;
}
pChannelMap[0]=ma_channel_map_init_standard_channel(standardChannelMap,Mh,iChannel);
pChannelMap+=1;
channelMapCap-=1;
}
}
MA_API Mv ma_channel_map_copy(ma_channel*pOut,const ma_channel*pIn,M3 Mh)
{
if (pOut !=NULL&&pIn !=NULL&&Mh>0) {
MA_COPY_MEMORY(pOut,pIn,sizeof(*pOut)*Mh);
}
}
MA_API Mv ma_channel_map_copy_or_default(ma_channel*pOut,size_t channelMapCapOut,const ma_channel*pIn,M3 Mh)
{
if (pOut==NULL||Mh==0) {
Mr;
}
if (pIn !=NULL) {
ma_channel_map_copy(pOut,pIn,Mh);
} else {
ma_channel_map_init_standard(ma_standard_channel_map_default,pOut,channelMapCapOut,Mh);
}
}
MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel*pChannelMap,M3 Mh)
{
if (Mh==0) {
Mr MA_FALSE;
}
if (Mh>1) {
M3 iChannel;
for (iChannel=0; iChannel<Mh;++iChannel) {
if (ma_channel_map_get_channel(pChannelMap,Mh,iChannel)==MA_CHANNEL_MONO) {
Mr MA_FALSE;
}
}
}
Mr MA_TRUE;
}
MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel*pChannelMapA,const ma_channel*pChannelMapB,M3 Mh)
{
M3 iChannel;
if (pChannelMapA==pChannelMapB) {
Mr MA_TRUE;
}
for (iChannel=0; iChannel<Mh;++iChannel) {
if (ma_channel_map_get_channel(pChannelMapA,Mh,iChannel) !=ma_channel_map_get_channel(pChannelMapB,Mh,iChannel)) {
Mr MA_FALSE;
}
}
Mr MA_TRUE;
}
MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel*pChannelMap,M3 Mh)
{
M3 iChannel;
if (pChannelMap==NULL) {
Mr MA_FALSE;
}
for (iChannel=0; iChannel<Mh;++iChannel) {
if (pChannelMap[iChannel] !=MA_CHANNEL_NONE) {
Mr MA_FALSE;
}
}
Mr MA_TRUE;
}
MA_API ma_bool32 ma_channel_map_contains_channel_position(M3 Mh,const ma_channel*pChannelMap,ma_channel channelPosition)
{
Mr ma_channel_map_find_channel_position(Mh,pChannelMap,channelPosition,NULL);
}
MA_API ma_bool32 ma_channel_map_find_channel_position(M3 Mh,const ma_channel*pChannelMap,ma_channel channelPosition,M3*pChannelIndex)
{
M3 iChannel;
if (pChannelIndex !=NULL) {
*pChannelIndex=(M3)-1;
}
for (iChannel=0; iChannel<Mh;++iChannel) {
if (ma_channel_map_get_channel(pChannelMap,Mh,iChannel)==channelPosition) {
if (pChannelIndex !=NULL) {
*pChannelIndex=iChannel;
}
Mr MA_TRUE;
}
}
Mr MA_FALSE;
}
MA_API size_t ma_channel_map_to_string(const ma_channel*pChannelMap,M3 Mh,char*pBufferOut,size_t bufferCap)
{
size_t len;
M3 iChannel;
len=0;
for (iChannel=0; iChannel<Mh; iChannel+=1) {
const char*pChannelStr=ma_channel_position_to_string(ma_channel_map_get_channel(pChannelMap,Mh,iChannel));
size_t channelStrLen=strlen(pChannelStr);
if (pBufferOut !=NULL&&bufferCap>len+channelStrLen) {
MA_COPY_MEMORY(pBufferOut+len,pChannelStr,channelStrLen);
}
len+=channelStrLen;
if (iChannel+1<Mh) {
if (pBufferOut !=NULL&&bufferCap>len+1) {
pBufferOut[len]=' ';
}
len+=1;
}
}
if (pBufferOut !=NULL&&bufferCap>len+1) {
pBufferOut[len]='\0';
}
Mr len;
}
MA_API const char*ma_channel_position_to_string(ma_channel channel)
{
switch (channel)
{
case MA_CHANNEL_NONE : Mr "CHANNEL_NONE";
case MA_CHANNEL_MONO : Mr "CHANNEL_MONO";
case MA_CHANNEL_FRONT_LEFT : Mr "CHANNEL_FRONT_LEFT";
case MA_CHANNEL_FRONT_RIGHT : Mr "CHANNEL_FRONT_RIGHT";
case MA_CHANNEL_FRONT_CENTER : Mr "CHANNEL_FRONT_CENTER";
case MA_CHANNEL_LFE : Mr "CHANNEL_LFE";
case MA_CHANNEL_BACK_LEFT : Mr "CHANNEL_BACK_LEFT";
case MA_CHANNEL_BACK_RIGHT : Mr "CHANNEL_BACK_RIGHT";
case MA_CHANNEL_FRONT_LEFT_CENTER : Mr "CHANNEL_FRONT_LEFT_CENTER";
case MA_CHANNEL_FRONT_RIGHT_CENTER: Mr "CHANNEL_FRONT_RIGHT_CENTER";
case MA_CHANNEL_BACK_CENTER : Mr "CHANNEL_BACK_CENTER";
case MA_CHANNEL_SIDE_LEFT : Mr "CHANNEL_SIDE_LEFT";
case MA_CHANNEL_SIDE_RIGHT : Mr "CHANNEL_SIDE_RIGHT";
case MA_CHANNEL_TOP_CENTER : Mr "CHANNEL_TOP_CENTER";
case MA_CHANNEL_TOP_FRONT_LEFT : Mr "CHANNEL_TOP_FRONT_LEFT";
case MA_CHANNEL_TOP_FRONT_CENTER : Mr "CHANNEL_TOP_FRONT_CENTER";
case MA_CHANNEL_TOP_FRONT_RIGHT : Mr "CHANNEL_TOP_FRONT_RIGHT";
case MA_CHANNEL_TOP_BACK_LEFT : Mr "CHANNEL_TOP_BACK_LEFT";
case MA_CHANNEL_TOP_BACK_CENTER : Mr "CHANNEL_TOP_BACK_CENTER";
case MA_CHANNEL_TOP_BACK_RIGHT : Mr "CHANNEL_TOP_BACK_RIGHT";
case MA_CHANNEL_AUX_0 : Mr "CHANNEL_AUX_0";
case MA_CHANNEL_AUX_1 : Mr "CHANNEL_AUX_1";
case MA_CHANNEL_AUX_2 : Mr "CHANNEL_AUX_2";
case MA_CHANNEL_AUX_3 : Mr "CHANNEL_AUX_3";
case MA_CHANNEL_AUX_4 : Mr "CHANNEL_AUX_4";
case MA_CHANNEL_AUX_5 : Mr "CHANNEL_AUX_5";
case MA_CHANNEL_AUX_6 : Mr "CHANNEL_AUX_6";
case MA_CHANNEL_AUX_7 : Mr "CHANNEL_AUX_7";
case MA_CHANNEL_AUX_8 : Mr "CHANNEL_AUX_8";
case MA_CHANNEL_AUX_9 : Mr "CHANNEL_AUX_9";
case MA_CHANNEL_AUX_10 : Mr "CHANNEL_AUX_10";
case MA_CHANNEL_AUX_11 : Mr "CHANNEL_AUX_11";
case MA_CHANNEL_AUX_12 : Mr "CHANNEL_AUX_12";
case MA_CHANNEL_AUX_13 : Mr "CHANNEL_AUX_13";
case MA_CHANNEL_AUX_14 : Mr "CHANNEL_AUX_14";
case MA_CHANNEL_AUX_15 : Mr "CHANNEL_AUX_15";
case MA_CHANNEL_AUX_16 : Mr "CHANNEL_AUX_16";
case MA_CHANNEL_AUX_17 : Mr "CHANNEL_AUX_17";
case MA_CHANNEL_AUX_18 : Mr "CHANNEL_AUX_18";
case MA_CHANNEL_AUX_19 : Mr "CHANNEL_AUX_19";
case MA_CHANNEL_AUX_20 : Mr "CHANNEL_AUX_20";
case MA_CHANNEL_AUX_21 : Mr "CHANNEL_AUX_21";
case MA_CHANNEL_AUX_22 : Mr "CHANNEL_AUX_22";
case MA_CHANNEL_AUX_23 : Mr "CHANNEL_AUX_23";
case MA_CHANNEL_AUX_24 : Mr "CHANNEL_AUX_24";
case MA_CHANNEL_AUX_25 : Mr "CHANNEL_AUX_25";
case MA_CHANNEL_AUX_26 : Mr "CHANNEL_AUX_26";
case MA_CHANNEL_AUX_27 : Mr "CHANNEL_AUX_27";
case MA_CHANNEL_AUX_28 : Mr "CHANNEL_AUX_28";
case MA_CHANNEL_AUX_29 : Mr "CHANNEL_AUX_29";
case MA_CHANNEL_AUX_30 : Mr "CHANNEL_AUX_30";
case MA_CHANNEL_AUX_31 : Mr "CHANNEL_AUX_31";
default:break;
}
Mr "UNKNOWN";
}
MA_API M6 ma_convert_frames(Mv*pOut,M6 frameCountOut,ma_format formatOut,M3 channelsOut,M3 sampleRateOut,const Mv*pIn,M6 frameCountIn,ma_format formatIn,M3 channelsIn,M3 sampleRateIn)
{
ma_data_converter_config config;
config=ma_data_converter_config_init(formatIn,formatOut,channelsIn,channelsOut,sampleRateIn,sampleRateOut);
config.resampling.linear.lpfOrder=ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER,MA_MAX_FILTER_ORDER);
Mr ma_convert_frames_ex(pOut,frameCountOut,pIn,frameCountIn,&config);
}
MA_API M6 ma_convert_frames_ex(Mv*pOut,M6 frameCountOut,const Mv*pIn,M6 frameCountIn,const ma_data_converter_config*Mo)
{
Me Mf;
ma_data_converter converter;
if (frameCountIn==0||Mo==NULL) {
Mr 0;
}
Mf=ma_data_converter_init(Mo,NULL,&converter);
if (Mf !=Ms) {
Mr 0;
}
if (pOut==NULL) {
Mf=ma_data_converter_get_expected_output_frame_count(&converter,frameCountIn,&frameCountOut);
if (Mf !=Ms) {
if (Mf==MA_NOT_IMPLEMENTED) {
frameCountOut=0;
while (frameCountIn>0) {
 M6 framesProcessedIn=frameCountIn;
 M6 framesProcessedOut=0xFFFFFFFF;
 Mf=ma_data_converter_process_pcm_frames(&converter,pIn,&framesProcessedIn,NULL,&framesProcessedOut);
 if (Mf !=Ms) {
 break;
 }
 frameCountIn-=framesProcessedIn;
}
}
}
} else {
Mf=ma_data_converter_process_pcm_frames(&converter,pIn,&frameCountIn,pOut,&frameCountOut);
if (Mf !=Ms) {
frameCountOut=0;
}
}
ma_data_converter_uninit(&converter,NULL);
Mr frameCountOut;
}
static MA_INLINE M3 ma_rb__extract_offset_in_bytes(M3 encodedOffset)
{
Mr encodedOffset&0x7FFFFFFF;
}
static MA_INLINE M3 ma_rb__extract_offset_loop_flag(M3 encodedOffset)
{
Mr encodedOffset&0x80000000;
}
static MA_INLINE Mv*ma_rb__get_read_ptr(ma_rb*pRB)
{
MA_ASSERT(pRB !=NULL);
Mr ma_offset_ptr(pRB->pBuffer,ma_rb__extract_offset_in_bytes(ma_atomic_load_32(&pRB->encodedReadOffset)));
}
static MA_INLINE Mv*ma_rb__get_write_ptr(ma_rb*pRB)
{
MA_ASSERT(pRB !=NULL);
Mr ma_offset_ptr(pRB->pBuffer,ma_rb__extract_offset_in_bytes(ma_atomic_load_32(&pRB->encodedWriteOffset)));
}
static MA_INLINE M3 ma_rb__construct_offset(M3 offsetInBytes,M3 offsetLoopFlag)
{
Mr offsetLoopFlag|offsetInBytes;
}
static MA_INLINE Mv ma_rb__deconstruct_offset(M3 encodedOffset,M3*pOffsetInBytes,M3*pOffsetLoopFlag)
{
MA_ASSERT(pOffsetInBytes !=NULL);
MA_ASSERT(pOffsetLoopFlag !=NULL);
*pOffsetInBytes=ma_rb__extract_offset_in_bytes(encodedOffset);
*pOffsetLoopFlag=ma_rb__extract_offset_loop_flag(encodedOffset);
}
MA_API Me ma_rb_init_ex(size_t subbufferSizeInBytes,size_t subbufferCount,size_t subbufferStrideInBytes,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_rb*pRB)
{
Me Mf;
const M3 maxSubBufferSize=0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1);
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
if (subbufferSizeInBytes==0||subbufferCount==0) {
Mr MA_INVALID_ARGS;
}
if (subbufferSizeInBytes>maxSubBufferSize) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pRB);
Mf=ma_allocation_callbacks_init_copy(&pRB->allocationCallbacks,pAllocationCallbacks);
if (Mf !=Ms) {
Mr Mf;
}
pRB->subbufferSizeInBytes=(M3)subbufferSizeInBytes;
pRB->subbufferCount=(M3)subbufferCount;
if (pOptionalPreallocatedBuffer !=NULL) {
pRB->subbufferStrideInBytes=(M3)subbufferStrideInBytes;
pRB->pBuffer=pOptionalPreallocatedBuffer;
} else {
size_t bufferSizeInBytes;
pRB->subbufferStrideInBytes=(pRB->subbufferSizeInBytes+(MA_SIMD_ALIGNMENT-1))&~MA_SIMD_ALIGNMENT;
bufferSizeInBytes=(size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes;
pRB->pBuffer=ma_aligned_malloc(bufferSizeInBytes,MA_SIMD_ALIGNMENT,&pRB->allocationCallbacks);
if (pRB->pBuffer==NULL) {
Mr MA_OUT_OF_MEMORY;
}
MA_ZERO_MEMORY(pRB->pBuffer,bufferSizeInBytes);
pRB->ownsBuffer=MA_TRUE;
}
Mr Ms;
}
MA_API Me ma_rb_init(size_t bufferSizeInBytes,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_rb*pRB)
{
Mr ma_rb_init_ex(bufferSizeInBytes,1,0,pOptionalPreallocatedBuffer,pAllocationCallbacks,pRB);
}
MA_API Mv ma_rb_uninit(ma_rb*pRB)
{
if (pRB==NULL) {
Mr;
}
if (pRB->ownsBuffer) {
ma_aligned_free(pRB->pBuffer,&pRB->allocationCallbacks);
}
}
MA_API Mv ma_rb_reset(ma_rb*pRB)
{
if (pRB==NULL) {
Mr;
}
ma_atomic_exchange_32(&pRB->encodedReadOffset,0);
ma_atomic_exchange_32(&pRB->encodedWriteOffset,0);
}
MA_API Me ma_rb_acquire_read(ma_rb*pRB,size_t*pSizeInBytes,Mv**ppBufferOut)
{
M3 writeOffset;
M3 writeOffsetInBytes;
M3 writeOffsetLoopFlag;
M3 readOffset;
M3 readOffsetInBytes;
M3 readOffsetLoopFlag;
size_t bytesAvailable;
size_t bytesRequested;
if (pRB==NULL||pSizeInBytes==NULL||ppBufferOut==NULL) {
Mr MA_INVALID_ARGS;
}
writeOffset=ma_atomic_load_32(&pRB->encodedWriteOffset);
ma_rb__deconstruct_offset(writeOffset,&writeOffsetInBytes,&writeOffsetLoopFlag);
readOffset=ma_atomic_load_32(&pRB->encodedReadOffset);
ma_rb__deconstruct_offset(readOffset,&readOffsetInBytes,&readOffsetLoopFlag);
if (readOffsetLoopFlag==writeOffsetLoopFlag) {
bytesAvailable=writeOffsetInBytes-readOffsetInBytes;
} else {
bytesAvailable=pRB->subbufferSizeInBytes-readOffsetInBytes;
}
bytesRequested=*pSizeInBytes;
if (bytesRequested>bytesAvailable) {
bytesRequested=bytesAvailable;
}
*pSizeInBytes=bytesRequested;
(*ppBufferOut)=ma_rb__get_read_ptr(pRB);
Mr Ms;
}
MA_API Me ma_rb_commit_read(ma_rb*pRB,size_t sizeInBytes)
{
M3 readOffset;
M3 readOffsetInBytes;
M3 readOffsetLoopFlag;
M3 newReadOffsetInBytes;
M3 newReadOffsetLoopFlag;
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
readOffset=ma_atomic_load_32(&pRB->encodedReadOffset);
ma_rb__deconstruct_offset(readOffset,&readOffsetInBytes,&readOffsetLoopFlag);
newReadOffsetInBytes=(M3)(readOffsetInBytes+sizeInBytes);
if (newReadOffsetInBytes>pRB->subbufferSizeInBytes) {
Mr MA_INVALID_ARGS;
}
newReadOffsetLoopFlag=readOffsetLoopFlag;
if (newReadOffsetInBytes==pRB->subbufferSizeInBytes) {
newReadOffsetInBytes=0;
newReadOffsetLoopFlag ^=0x80000000;
}
ma_atomic_exchange_32(&pRB->encodedReadOffset,ma_rb__construct_offset(newReadOffsetInBytes,newReadOffsetLoopFlag));
Mr Ms;
}
MA_API Me ma_rb_acquire_write(ma_rb*pRB,size_t*pSizeInBytes,Mv**ppBufferOut)
{
M3 readOffset;
M3 readOffsetInBytes;
M3 readOffsetLoopFlag;
M3 writeOffset;
M3 writeOffsetInBytes;
M3 writeOffsetLoopFlag;
size_t bytesAvailable;
size_t bytesRequested;
if (pRB==NULL||pSizeInBytes==NULL||ppBufferOut==NULL) {
Mr MA_INVALID_ARGS;
}
readOffset=ma_atomic_load_32(&pRB->encodedReadOffset);
ma_rb__deconstruct_offset(readOffset,&readOffsetInBytes,&readOffsetLoopFlag);
writeOffset=ma_atomic_load_32(&pRB->encodedWriteOffset);
ma_rb__deconstruct_offset(writeOffset,&writeOffsetInBytes,&writeOffsetLoopFlag);
if (writeOffsetLoopFlag==readOffsetLoopFlag) {
bytesAvailable=pRB->subbufferSizeInBytes-writeOffsetInBytes;
} else {
bytesAvailable=readOffsetInBytes-writeOffsetInBytes;
}
bytesRequested=*pSizeInBytes;
if (bytesRequested>bytesAvailable) {
bytesRequested=bytesAvailable;
}
*pSizeInBytes=bytesRequested;
*ppBufferOut=ma_rb__get_write_ptr(pRB);
if (pRB->clearOnWriteAcquire) {
MA_ZERO_MEMORY(*ppBufferOut,*pSizeInBytes);
}
Mr Ms;
}
MA_API Me ma_rb_commit_write(ma_rb*pRB,size_t sizeInBytes)
{
M3 writeOffset;
M3 writeOffsetInBytes;
M3 writeOffsetLoopFlag;
M3 newWriteOffsetInBytes;
M3 newWriteOffsetLoopFlag;
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
writeOffset=ma_atomic_load_32(&pRB->encodedWriteOffset);
ma_rb__deconstruct_offset(writeOffset,&writeOffsetInBytes,&writeOffsetLoopFlag);
newWriteOffsetInBytes=(M3)(writeOffsetInBytes+sizeInBytes);
if (newWriteOffsetInBytes>pRB->subbufferSizeInBytes) {
Mr MA_INVALID_ARGS;
}
newWriteOffsetLoopFlag=writeOffsetLoopFlag;
if (newWriteOffsetInBytes==pRB->subbufferSizeInBytes) {
newWriteOffsetInBytes=0;
newWriteOffsetLoopFlag ^=0x80000000;
}
ma_atomic_exchange_32(&pRB->encodedWriteOffset,ma_rb__construct_offset(newWriteOffsetInBytes,newWriteOffsetLoopFlag));
Mr Ms;
}
MA_API Me ma_rb_seek_read(ma_rb*pRB,size_t offsetInBytes)
{
M3 readOffset;
M3 readOffsetInBytes;
M3 readOffsetLoopFlag;
M3 writeOffset;
M3 writeOffsetInBytes;
M3 writeOffsetLoopFlag;
M3 newReadOffsetInBytes;
M3 newReadOffsetLoopFlag;
if (pRB==NULL||offsetInBytes>pRB->subbufferSizeInBytes) {
Mr MA_INVALID_ARGS;
}
readOffset=ma_atomic_load_32(&pRB->encodedReadOffset);
ma_rb__deconstruct_offset(readOffset,&readOffsetInBytes,&readOffsetLoopFlag);
writeOffset=ma_atomic_load_32(&pRB->encodedWriteOffset);
ma_rb__deconstruct_offset(writeOffset,&writeOffsetInBytes,&writeOffsetLoopFlag);
newReadOffsetLoopFlag=readOffsetLoopFlag;
if (readOffsetLoopFlag==writeOffsetLoopFlag) {
if ((readOffsetInBytes+offsetInBytes)>writeOffsetInBytes) {
newReadOffsetInBytes=writeOffsetInBytes;
} else {
newReadOffsetInBytes=(M3)(readOffsetInBytes+offsetInBytes);
}
} else {
if ((readOffsetInBytes+offsetInBytes)>=pRB->subbufferSizeInBytes) {
newReadOffsetInBytes=(M3)(readOffsetInBytes+offsetInBytes)-pRB->subbufferSizeInBytes;
newReadOffsetLoopFlag ^=0x80000000;
} else {
newReadOffsetInBytes=(M3)(readOffsetInBytes+offsetInBytes);
}
}
ma_atomic_exchange_32(&pRB->encodedReadOffset,ma_rb__construct_offset(newReadOffsetInBytes,newReadOffsetLoopFlag));
Mr Ms;
}
MA_API Me ma_rb_seek_write(ma_rb*pRB,size_t offsetInBytes)
{
M3 readOffset;
M3 readOffsetInBytes;
M3 readOffsetLoopFlag;
M3 writeOffset;
M3 writeOffsetInBytes;
M3 writeOffsetLoopFlag;
M3 newWriteOffsetInBytes;
M3 newWriteOffsetLoopFlag;
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
readOffset=ma_atomic_load_32(&pRB->encodedReadOffset);
ma_rb__deconstruct_offset(readOffset,&readOffsetInBytes,&readOffsetLoopFlag);
writeOffset=ma_atomic_load_32(&pRB->encodedWriteOffset);
ma_rb__deconstruct_offset(writeOffset,&writeOffsetInBytes,&writeOffsetLoopFlag);
newWriteOffsetLoopFlag=writeOffsetLoopFlag;
if (readOffsetLoopFlag==writeOffsetLoopFlag) {
if ((writeOffsetInBytes+offsetInBytes)>=pRB->subbufferSizeInBytes) {
newWriteOffsetInBytes=(M3)(writeOffsetInBytes+offsetInBytes)-pRB->subbufferSizeInBytes;
newWriteOffsetLoopFlag ^=0x80000000;
} else {
newWriteOffsetInBytes=(M3)(writeOffsetInBytes+offsetInBytes);
}
} else {
if ((writeOffsetInBytes+offsetInBytes)>readOffsetInBytes) {
newWriteOffsetInBytes=readOffsetInBytes;
} else {
newWriteOffsetInBytes=(M3)(writeOffsetInBytes+offsetInBytes);
}
}
ma_atomic_exchange_32(&pRB->encodedWriteOffset,ma_rb__construct_offset(newWriteOffsetInBytes,newWriteOffsetLoopFlag));
Mr Ms;
}
MA_API ma_int32 ma_rb_pointer_distance(ma_rb*pRB)
{
M3 readOffset;
M3 readOffsetInBytes;
M3 readOffsetLoopFlag;
M3 writeOffset;
M3 writeOffsetInBytes;
M3 writeOffsetLoopFlag;
if (pRB==NULL) {
Mr 0;
}
readOffset=ma_atomic_load_32(&pRB->encodedReadOffset);
ma_rb__deconstruct_offset(readOffset,&readOffsetInBytes,&readOffsetLoopFlag);
writeOffset=ma_atomic_load_32(&pRB->encodedWriteOffset);
ma_rb__deconstruct_offset(writeOffset,&writeOffsetInBytes,&writeOffsetLoopFlag);
if (readOffsetLoopFlag==writeOffsetLoopFlag) {
Mr writeOffsetInBytes-readOffsetInBytes;
} else {
Mr writeOffsetInBytes+(pRB->subbufferSizeInBytes-readOffsetInBytes);
}
}
MA_API M3 ma_rb_available_read(ma_rb*pRB)
{
ma_int32 dist;
if (pRB==NULL) {
Mr 0;
}
dist=ma_rb_pointer_distance(pRB);
if (dist<0) {
Mr 0;
}
Mr dist;
}
MA_API M3 ma_rb_available_write(ma_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr (M3)(ma_rb_get_subbuffer_size(pRB)-ma_rb_pointer_distance(pRB));
}
MA_API size_t ma_rb_get_subbuffer_size(ma_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr pRB->subbufferSizeInBytes;
}
MA_API size_t ma_rb_get_subbuffer_stride(ma_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
if (pRB->subbufferStrideInBytes==0) {
Mr (size_t)pRB->subbufferSizeInBytes;
}
Mr (size_t)pRB->subbufferStrideInBytes;
}
MA_API size_t ma_rb_get_subbuffer_offset(ma_rb*pRB,size_t subbufferIndex)
{
if (pRB==NULL) {
Mr 0;
}
Mr subbufferIndex*ma_rb_get_subbuffer_stride(pRB);
}
MA_API Mv*ma_rb_get_subbuffer_ptr(ma_rb*pRB,size_t subbufferIndex,Mv*pBuffer)
{
if (pRB==NULL) {
Mr NULL;
}
Mr ma_offset_ptr(pBuffer,ma_rb_get_subbuffer_offset(pRB,subbufferIndex));
}
static Me ma_pcm_rb_data_source__on_read(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
ma_pcm_rb*pRB=(ma_pcm_rb*)pDataSource;
Me Mf;
M6 totalFramesRead;
MA_ASSERT(pRB !=NULL);
totalFramesRead=0;
while (totalFramesRead<frameCount) {
Mv*pMappedBuffer;
M3 mappedFrameCount;
M6 framesToRead=frameCount-totalFramesRead;
if (framesToRead>0xFFFFFFFF) {
framesToRead=0xFFFFFFFF;
}
mappedFrameCount=(M3)framesToRead;
Mf=ma_pcm_rb_acquire_read(pRB,&mappedFrameCount,&pMappedBuffer);
if (Mf !=Ms) {
break;
}
if (mappedFrameCount==0) {
break;
}
ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut,totalFramesRead,pRB->format,pRB->Mh),pMappedBuffer,mappedFrameCount,pRB->format,pRB->Mh);
Mf=ma_pcm_rb_commit_read(pRB,mappedFrameCount);
if (Mf !=Ms) {
break;
}
totalFramesRead+=mappedFrameCount;
}
if (totalFramesRead<frameCount) {
ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut,totalFramesRead,pRB->format,pRB->Mh),(frameCount-totalFramesRead),pRB->format,pRB->Mh);
totalFramesRead=frameCount;
}
*pFramesRead=totalFramesRead;
Mr Ms;
}
static Me ma_pcm_rb_data_source__on_get_data_format(ma_data_source*pDataSource,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap)
{
ma_pcm_rb*pRB=(ma_pcm_rb*)pDataSource;
MA_ASSERT(pRB !=NULL);
if (pFormat !=NULL) {
*pFormat=pRB->format;
}
if (pChannels !=NULL) {
*pChannels=pRB->Mh;
}
if (pSampleRate !=NULL) {
*pSampleRate=pRB->sampleRate;
}
if (pChannelMap !=NULL) {
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,pRB->Mh);
}
Mr Ms;
}
static ma_data_source_vtable ma_gRBDataSourceVTable=
{
ma_pcm_rb_data_source__on_read,NULL,ma_pcm_rb_data_source__on_get_data_format,NULL,NULL,NULL,0
};
static MA_INLINE M3 ma_pcm_rb_get_bpf(ma_pcm_rb*pRB)
{
MA_ASSERT(pRB !=NULL);
Mr ma_get_bytes_per_frame(pRB->format,pRB->Mh);
}
MA_API Me ma_pcm_rb_init_ex(ma_format format,M3 Mh,M3 subbufferSizeInFrames,M3 subbufferCount,M3 subbufferStrideInFrames,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_pcm_rb*pRB)
{
M3 bpf;
Me Mf;
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pRB);
bpf=ma_get_bytes_per_frame(format,Mh);
if (bpf==0) {
Mr MA_INVALID_ARGS;
}
Mf=ma_rb_init_ex(subbufferSizeInFrames*bpf,subbufferCount,subbufferStrideInFrames*bpf,pOptionalPreallocatedBuffer,pAllocationCallbacks,&pRB->rb);
if (Mf !=Ms) {
Mr Mf;
}
pRB->format=format;
pRB->Mh=Mh;
pRB->sampleRate=0;
{
ma_data_source_config dataSourceConfig=ma_data_source_config_init();
dataSourceConfig.vtable=&ma_gRBDataSourceVTable;
Mf=ma_data_source_init(&dataSourceConfig,&pRB->ds);
if (Mf !=Ms) {
ma_rb_uninit(&pRB->rb);
Mr Mf;
}
}
Mr Ms;
}
MA_API Me ma_pcm_rb_init(ma_format format,M3 Mh,M3 bufferSizeInFrames,Mv*pOptionalPreallocatedBuffer,const ma_allocation_callbacks*pAllocationCallbacks,ma_pcm_rb*pRB)
{
Mr ma_pcm_rb_init_ex(format,Mh,bufferSizeInFrames,1,0,pOptionalPreallocatedBuffer,pAllocationCallbacks,pRB);
}
MA_API Mv ma_pcm_rb_uninit(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr;
}
ma_data_source_uninit(&pRB->ds);
ma_rb_uninit(&pRB->rb);
}
MA_API Mv ma_pcm_rb_reset(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr;
}
ma_rb_reset(&pRB->rb);
}
MA_API Me ma_pcm_rb_acquire_read(ma_pcm_rb*pRB,M3*pSizeInFrames,Mv**ppBufferOut)
{
size_t sizeInBytes;
Me Mf;
if (pRB==NULL||pSizeInFrames==NULL) {
Mr MA_INVALID_ARGS;
}
sizeInBytes=*pSizeInFrames*ma_pcm_rb_get_bpf(pRB);
Mf=ma_rb_acquire_read(&pRB->rb,&sizeInBytes,ppBufferOut);
if (Mf !=Ms) {
Mr Mf;
}
*pSizeInFrames=(M3)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB));
Mr Ms;
}
MA_API Me ma_pcm_rb_commit_read(ma_pcm_rb*pRB,M3 sizeInFrames)
{
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_rb_commit_read(&pRB->rb,sizeInFrames*ma_pcm_rb_get_bpf(pRB));
}
MA_API Me ma_pcm_rb_acquire_write(ma_pcm_rb*pRB,M3*pSizeInFrames,Mv**ppBufferOut)
{
size_t sizeInBytes;
Me Mf;
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
sizeInBytes=*pSizeInFrames*ma_pcm_rb_get_bpf(pRB);
Mf=ma_rb_acquire_write(&pRB->rb,&sizeInBytes,ppBufferOut);
if (Mf !=Ms) {
Mr Mf;
}
*pSizeInFrames=(M3)(sizeInBytes / ma_pcm_rb_get_bpf(pRB));
Mr Ms;
}
MA_API Me ma_pcm_rb_commit_write(ma_pcm_rb*pRB,M3 sizeInFrames)
{
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_rb_commit_write(&pRB->rb,sizeInFrames*ma_pcm_rb_get_bpf(pRB));
}
MA_API Me ma_pcm_rb_seek_read(ma_pcm_rb*pRB,M3 offsetInFrames)
{
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_rb_seek_read(&pRB->rb,offsetInFrames*ma_pcm_rb_get_bpf(pRB));
}
MA_API Me ma_pcm_rb_seek_write(ma_pcm_rb*pRB,M3 offsetInFrames)
{
if (pRB==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_rb_seek_write(&pRB->rb,offsetInFrames*ma_pcm_rb_get_bpf(pRB));
}
MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr ma_rb_pointer_distance(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
}
MA_API M3 ma_pcm_rb_available_read(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr ma_rb_available_read(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
}
MA_API M3 ma_pcm_rb_available_write(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr ma_rb_available_write(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
}
MA_API M3 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr (M3)(ma_rb_get_subbuffer_size(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
}
MA_API M3 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr (M3)(ma_rb_get_subbuffer_stride(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
}
MA_API M3 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb*pRB,M3 subbufferIndex)
{
if (pRB==NULL) {
Mr 0;
}
Mr (M3)(ma_rb_get_subbuffer_offset(&pRB->rb,subbufferIndex) / ma_pcm_rb_get_bpf(pRB));
}
MA_API Mv*ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb*pRB,M3 subbufferIndex,Mv*pBuffer)
{
if (pRB==NULL) {
Mr NULL;
}
Mr ma_rb_get_subbuffer_ptr(&pRB->rb,subbufferIndex,pBuffer);
}
MA_API ma_format ma_pcm_rb_get_format(const ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr ma_format_unknown;
}
Mr pRB->format;
}
MA_API M3 ma_pcm_rb_get_channels(const ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr pRB->Mh;
}
MA_API M3 ma_pcm_rb_get_sample_rate(const ma_pcm_rb*pRB)
{
if (pRB==NULL) {
Mr 0;
}
Mr pRB->sampleRate;
}
MA_API Mv ma_pcm_rb_set_sample_rate(ma_pcm_rb*pRB,M3 sampleRate)
{
if (pRB==NULL) {
Mr;
}
pRB->sampleRate=sampleRate;
}
MA_API Me ma_duplex_rb_init(ma_format captureFormat,M3 captureChannels,M3 sampleRate,M3 captureInternalSampleRate,M3 captureInternalPeriodSizeInFrames,const ma_allocation_callbacks*pAllocationCallbacks,ma_duplex_rb*pRB)
{
Me Mf;
M3 sizeInFrames;
sizeInFrames=(M3)ma_calculate_frame_count_after_resampling(sampleRate,captureInternalSampleRate,captureInternalPeriodSizeInFrames*5);
if (sizeInFrames==0) {
Mr MA_INVALID_ARGS;
}
Mf=ma_pcm_rb_init(captureFormat,captureChannels,sizeInFrames,NULL,pAllocationCallbacks,&pRB->rb);
if (Mf !=Ms) {
Mr Mf;
}
ma_pcm_rb_seek_write((ma_pcm_rb*)pRB,captureInternalPeriodSizeInFrames*2);
Mr Ms;
}
MA_API Me ma_duplex_rb_uninit(ma_duplex_rb*pRB)
{
ma_pcm_rb_uninit((ma_pcm_rb*)pRB);
Mr Ms;
}
MA_API const char*ma_result_description(Me Mf)
{
switch (Mf)
{
case Ms: Mr "No error";
case MA_ERROR: Mr "Unknown error";
case MA_INVALID_ARGS: Mr "Invalid argument";
case MA_INVALID_OPERATION: Mr "Invalid operation";
case MA_OUT_OF_MEMORY: Mr "Out of memory";
case MA_OUT_OF_RANGE: Mr "Out of range";
case MA_ACCESS_DENIED: Mr "Permission denied";
case MA_DOES_NOT_EXIST: Mr "Resource does not exist";
case MA_ALREADY_EXISTS: Mr "Resource already exists";
case MA_TOO_MANY_OPEN_FILES: Mr "Too many open files";
case MA_INVALID_FILE: Mr "Invalid file";
case MA_TOO_BIG: Mr "Too large";
case MA_PATH_TOO_LONG: Mr "Path too long";
case MA_NAME_TOO_LONG: Mr "Name too long";
case MA_NOT_DIRECTORY: Mr "Not a directory";
case MA_IS_DIRECTORY: Mr "Is a directory";
case MA_DIRECTORY_NOT_EMPTY: Mr "Directory not empty";
case MA_AT_END: Mr "At end";
case MA_NO_SPACE: Mr "No space available";
case MA_BUSY: Mr "Device or resource busy";
case MA_IO_ERROR: Mr "Input/output error";
case MA_INTERRUPT: Mr "Interrupted";
case MA_UNAVAILABLE: Mr "Resource unavailable";
case MA_ALREADY_IN_USE: Mr "Resource already in use";
case MA_BAD_ADDRESS: Mr "Bad address";
case MA_BAD_SEEK: Mr "Illegal seek";
case MA_BAD_PIPE: Mr "Broken pipe";
case MA_DEADLOCK: Mr "Deadlock";
case MA_TOO_MANY_LINKS: Mr "Too many links";
case MA_NOT_IMPLEMENTED: Mr "Not implemented";
case MA_NO_MESSAGE: Mr "No message of desired type";
case MA_BAD_MESSAGE: Mr "Invalid message";
case MA_NO_DATA_AVAILABLE: Mr "No data available";
case MA_INVALID_DATA: Mr "Invalid data";
case MA_TIMEOUT: Mr "Timeout";
case MA_NO_NETWORK: Mr "Network unavailable";
case MA_NOT_UNIQUE: Mr "Not unique";
case MA_NOT_SOCKET: Mr "Socket operation on non-socket";
case MA_NO_ADDRESS: Mr "Destination address required";
case MA_BAD_PROTOCOL: Mr "Protocol wrong type for socket";
case MA_PROTOCOL_UNAVAILABLE: Mr "Protocol not available";
case MA_PROTOCOL_NOT_SUPPORTED: Mr "Protocol not supported";
case MA_PROTOCOL_FAMILY_NOT_SUPPORTED: Mr "Protocol family not supported";
case MA_ADDRESS_FAMILY_NOT_SUPPORTED: Mr "Address family not supported";
case MA_SOCKET_NOT_SUPPORTED: Mr "Socket type not supported";
case MA_CONNECTION_RESET: Mr "Connection reset";
case MA_ALREADY_CONNECTED: Mr "Already connected";
case MA_NOT_CONNECTED: Mr "Not connected";
case MA_CONNECTION_REFUSED: Mr "Connection refused";
case MA_NO_HOST: Mr "No host";
case MA_IN_PROGRESS: Mr "Operation in progress";
case MA_CANCELLED: Mr "Operation cancelled";
case MA_MEMORY_ALREADY_MAPPED: Mr "Memory already mapped";
case MA_FORMAT_NOT_SUPPORTED: Mr "Format not supported";
case MA_DEVICE_TYPE_NOT_SUPPORTED: Mr "Device type not supported";
case MA_SHARE_MODE_NOT_SUPPORTED: Mr "Share mode not supported";
case MA_NO_BACKEND: Mr "No backend";
case MA_NO_DEVICE: Mr "No device";
case MA_API_NOT_FOUND: Mr "API not found";
case MA_INVALID_DEVICE_CONFIG: Mr "Invalid device config";
case MA_DEVICE_NOT_INITIALIZED: Mr "Device not initialized";
case MA_DEVICE_NOT_STARTED: Mr "Device not started";
case MA_FAILED_TO_INIT_BACKEND: Mr "Failed to initialize backend";
case MA_FAILED_TO_OPEN_BACKEND_DEVICE: Mr "Failed to open backend device";
case MA_FAILED_TO_START_BACKEND_DEVICE: Mr "Failed to start backend device";
case MA_FAILED_TO_STOP_BACKEND_DEVICE: Mr "Failed to stop backend device";
default: Mr "Unknown error";
}
}
MA_API Mv*ma_malloc(size_t sz,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pAllocationCallbacks !=NULL) {
if (pAllocationCallbacks->onMalloc !=NULL) {
Mr pAllocationCallbacks->onMalloc(sz,pAllocationCallbacks->pUserData);
} else {
Mr NULL;
}
} else {
Mr ma__malloc_default(sz,NULL);
}
}
MA_API Mv*ma_calloc(size_t sz,const ma_allocation_callbacks*pAllocationCallbacks)
{
Mv*p=ma_malloc(sz,pAllocationCallbacks);
if (p !=NULL) {
MA_ZERO_MEMORY(p,sz);
}
Mr p;
}
MA_API Mv*ma_realloc(Mv*p,size_t sz,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pAllocationCallbacks !=NULL) {
if (pAllocationCallbacks->onRealloc !=NULL) {
Mr pAllocationCallbacks->onRealloc(p,sz,pAllocationCallbacks->pUserData);
} else {
Mr NULL;
}
} else {
Mr ma__realloc_default(p,sz,NULL);
}
}
MA_API Mv ma_free(Mv*p,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (p==NULL) {
Mr;
}
if (pAllocationCallbacks !=NULL) {
if (pAllocationCallbacks->onFree !=NULL) {
pAllocationCallbacks->onFree(p,pAllocationCallbacks->pUserData);
} else {
Mr;
}
} else {
ma__free_default(p,NULL);
}
}
MA_API Mv*ma_aligned_malloc(size_t sz,size_t alignment,const ma_allocation_callbacks*pAllocationCallbacks)
{
size_t extraBytes;
Mv*pUnaligned;
Mv*pAligned;
if (alignment==0) {
Mr 0;
}
extraBytes=alignment-1+sizeof(Mv*);
pUnaligned=ma_malloc(sz+extraBytes,pAllocationCallbacks);
if (pUnaligned==NULL) {
Mr NULL;
}
pAligned=(Mv*)(((ma_uintptr)pUnaligned+extraBytes)&~((ma_uintptr)(alignment-1)));
((Mv**)pAligned)[-1]=pUnaligned;
Mr pAligned;
}
MA_API Mv ma_aligned_free(Mv*p,const ma_allocation_callbacks*pAllocationCallbacks)
{
ma_free(((Mv**)p)[-1],pAllocationCallbacks);
}
MA_API const char*ma_get_format_name(ma_format format)
{
switch (format)
{
case ma_format_unknown: Mr "Unknown";
case ma_format_u8: Mr "8-bit Unsigned Integer";
case ma_format_s16: Mr "16-bit Signed Integer";
case ma_format_s24: Mr "24-bit Signed Integer (Tightly Packed)";
case ma_format_s32: Mr "32-bit Signed Integer";
case ma_format_f32: Mr "32-bit IEEE Floating Point";
default: Mr "Invalid";
}
}
MA_API Mv ma_blend_f32(float*pOut,float*pInA,float*pInB,float factor,M3 Mh)
{
M3 i;
for (i=0; i<Mh;++i) {
pOut[i]=ma_mix_f32(pInA[i],pInB[i],factor);
}
}
MA_API M3 ma_get_bytes_per_sample(ma_format format)
{
M3 sizes[]={
0,1,2,3,4,4,};
Mr sizes[format];
}
#define MA_DATA_SOURCE_DEFAULT_RANGE_BEG 0
#define MA_DATA_SOURCE_DEFAULT_RANGE_END ~((M6)0)
#define MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG 0
#define MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END ~((M6)0)
MA_API ma_data_source_config ma_data_source_config_init(Mv)
{
ma_data_source_config config;
MA_ZERO_OBJECT(&config);
Mr config;
}
MA_API Me ma_data_source_init(const ma_data_source_config*Mo,ma_data_source*pDataSource)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pDataSourceBase);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->vtable==NULL) {
Mr MA_INVALID_ARGS;
}
pDataSourceBase->vtable=Mo->vtable;
pDataSourceBase->rangeBegInFrames=MA_DATA_SOURCE_DEFAULT_RANGE_BEG;
pDataSourceBase->rangeEndInFrames=MA_DATA_SOURCE_DEFAULT_RANGE_END;
pDataSourceBase->loopBegInFrames=MA_DATA_SOURCE_DEFAULT_LOOP_POINT_BEG;
pDataSourceBase->loopEndInFrames=MA_DATA_SOURCE_DEFAULT_LOOP_POINT_END;
pDataSourceBase->pCurrent=pDataSource;
pDataSourceBase->pNext=NULL;
pDataSourceBase->onGetNext=NULL;
Mr Ms;
}
MA_API Mv ma_data_source_uninit(ma_data_source*pDataSource)
{
if (pDataSource==NULL) {
Mr;
}
}
static Me ma_data_source_resolve_current(ma_data_source*pDataSource,ma_data_source**ppCurrentDataSource)
{
ma_data_source_base*pCurrentDataSource=(ma_data_source_base*)pDataSource;
MA_ASSERT(pDataSource !=NULL);
MA_ASSERT(ppCurrentDataSource !=NULL);
if (pCurrentDataSource->pCurrent==NULL) {
if (pCurrentDataSource->pNext !=NULL||pCurrentDataSource->onGetNext !=NULL) {
pCurrentDataSource=NULL;
} else {
pCurrentDataSource=(ma_data_source_base*)pDataSource;
}
} else {
pCurrentDataSource=(ma_data_source_base*)pCurrentDataSource->pCurrent;
}
*ppCurrentDataSource=pCurrentDataSource;
Mr Ms;
}
static Me ma_data_source_read_pcm_frames_from_backend(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
MA_ASSERT(pDataSourceBase !=NULL);
MA_ASSERT(pDataSourceBase->vtable !=NULL);
MA_ASSERT(pDataSourceBase->vtable->onRead !=NULL);
MA_ASSERT(pFramesRead !=NULL);
if (pFramesOut !=NULL) {
Mr pDataSourceBase->vtable->onRead(pDataSourceBase,pFramesOut,frameCount,pFramesRead);
} else {
Me Mf;
M6 framesRead;
ma_format format;
M3 Mh;
M6 discardBufferCapInFrames;
ma_uint8 pDiscardBuffer[4096];
Mf=ma_data_source_get_data_format(pDataSource,&format,&Mh,NULL,NULL,0);
if (Mf !=Ms) {
Mr Mf;
}
discardBufferCapInFrames=sizeof(pDiscardBuffer) / ma_get_bytes_per_frame(format,Mh);
framesRead=0;
while (framesRead<frameCount) {
M6 framesReadThisIteration=0;
M6 framesToRead=frameCount-framesRead;
if (framesToRead>discardBufferCapInFrames) {
framesToRead=discardBufferCapInFrames;
}
Mf=pDataSourceBase->vtable->onRead(pDataSourceBase,pDiscardBuffer,framesToRead,&framesReadThisIteration);
if (Mf !=Ms) {
Mr Mf;
}
framesRead+=framesReadThisIteration;
}
*pFramesRead=framesRead;
Mr Ms;
}
}
static Me ma_data_source_read_pcm_frames_within_range(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
Me Mf;
M6 framesRead=0;
ma_bool32 loop=ma_data_source_is_looping(pDataSource);
if (pDataSourceBase==NULL) {
Mr MA_AT_END;
}
if (frameCount==0) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(pDataSourceBase->vtable !=NULL);
if ((pDataSourceBase->vtable->flags&MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) !=0||(pDataSourceBase->rangeEndInFrames==~((M6)0)&&(pDataSourceBase->loopEndInFrames==~((M6)0)||loop==MA_FALSE))) {
Mf=ma_data_source_read_pcm_frames_from_backend(pDataSource,pFramesOut,frameCount,&framesRead);
} else {
M6 relativeCursor;
M6 absoluteCursor;
Mf=ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase,&relativeCursor);
if (Mf !=Ms) {
Mf=ma_data_source_read_pcm_frames_from_backend(pDataSource,pFramesOut,frameCount,&framesRead);
} else {
M6 rangeBeg;
M6 rangeEnd;
rangeBeg=pDataSourceBase->rangeBegInFrames;
rangeEnd=pDataSourceBase->rangeEndInFrames;
absoluteCursor=rangeBeg+relativeCursor;
if (loop) {
if (pDataSourceBase->loopEndInFrames !=~((M6)0)) {
 rangeEnd=ma_min(rangeEnd,pDataSourceBase->rangeBegInFrames+pDataSourceBase->loopEndInFrames);
}
}
if (frameCount>(rangeEnd-absoluteCursor)&&rangeEnd !=~((M6)0)) {
frameCount=(rangeEnd-absoluteCursor);
}
if (frameCount>0) {
Mf=ma_data_source_read_pcm_frames_from_backend(pDataSource,pFramesOut,frameCount,&framesRead);
} else {
Mf=MA_AT_END;
}
}
}
if (pFramesRead !=NULL) {
*pFramesRead=framesRead;
}
if (Mf==Ms&&framesRead==0) {
Mf=MA_AT_END;
}
Mr Mf;
}
MA_API Me ma_data_source_read_pcm_frames(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
Me Mf=Ms;
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
ma_data_source_base*pCurrentDataSource;
Mv*pRunningFramesOut=pFramesOut;
M6 totalFramesProcessed=0;
ma_format format;
M3 Mh;
M3 emptyLoopCounter=0;
ma_bool32 loop;
if (pFramesRead !=NULL) {
*pFramesRead=0;
}
if (frameCount==0) {
Mr MA_INVALID_ARGS;
}
if (pDataSourceBase==NULL) {
Mr MA_INVALID_ARGS;
}
loop=ma_data_source_is_looping(pDataSource);
if (ma_data_source_get_data_format(pDataSource,&format,&Mh,NULL,NULL,0) !=Ms) {
Mf=ma_data_source_resolve_current(pDataSource,(ma_data_source**)&pCurrentDataSource);
if (Mf !=Ms) {
Mr Mf;
}
Mr ma_data_source_read_pcm_frames_within_range(pCurrentDataSource,pFramesOut,frameCount,pFramesRead);
}
while (totalFramesProcessed<frameCount) {
M6 framesProcessed;
M6 framesRemaining=frameCount-totalFramesProcessed;
Mf=ma_data_source_resolve_current(pDataSource,(ma_data_source**)&pCurrentDataSource);
if (Mf !=Ms) {
break;
}
if (pCurrentDataSource==NULL) {
break;
}
Mf=ma_data_source_read_pcm_frames_within_range(pCurrentDataSource,pRunningFramesOut,framesRemaining,&framesProcessed);
totalFramesProcessed+=framesProcessed;
if (Mf !=Ms&&Mf !=MA_AT_END) {
break;
}
if (Mf==MA_AT_END) {
Mf=Ms;
if (loop) {
if (framesProcessed==0) {
 emptyLoopCounter+=1;
 if (emptyLoopCounter>1) {
 break;
 }
} else {
 emptyLoopCounter=0;
}
Mf=ma_data_source_seek_to_pcm_frame(pCurrentDataSource,pCurrentDataSource->loopBegInFrames);
if (Mf !=Ms) {
 break;
}
Mf=Ms;
} else {
if (pCurrentDataSource->pNext !=NULL) {
 pDataSourceBase->pCurrent=pCurrentDataSource->pNext;
} else if (pCurrentDataSource->onGetNext !=NULL) {
 pDataSourceBase->pCurrent=pCurrentDataSource->onGetNext(pCurrentDataSource);
 if (pDataSourceBase->pCurrent==NULL) {
 break;
 }
} else {
 break;
}
Mf=ma_data_source_seek_to_pcm_frame(pDataSourceBase->pCurrent,0);
if (Mf !=Ms) {
 break;
}
}
}
if (pRunningFramesOut !=NULL) {
pRunningFramesOut=ma_offset_ptr(pRunningFramesOut,framesProcessed*ma_get_bytes_per_frame(format,Mh));
}
}
if (pFramesRead !=NULL) {
*pFramesRead=totalFramesProcessed;
}
MA_ASSERT(!(Mf==MA_AT_END&&totalFramesProcessed>0));
if (Mf==Ms&&totalFramesProcessed==0) {
Mf=MA_AT_END;
}
Mr Mf;
}
MA_API Me ma_data_source_seek_pcm_frames(ma_data_source*pDataSource,M6 frameCount,M6*pFramesSeeked)
{
Mr ma_data_source_read_pcm_frames(pDataSource,NULL,frameCount,pFramesSeeked);
}
MA_API Me ma_data_source_seek_to_pcm_frame(ma_data_source*pDataSource,M6 frameIndex)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSourceBase==NULL) {
Mr MA_INVALID_ARGS;
}
if (pDataSourceBase->vtable->onSeek==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
if (frameIndex>pDataSourceBase->rangeEndInFrames) {
Mr MA_INVALID_OPERATION;
}
MA_ASSERT(pDataSourceBase->vtable !=NULL);
Mr pDataSourceBase->vtable->onSeek(pDataSource,pDataSourceBase->rangeBegInFrames+frameIndex);
}
MA_API Me ma_data_source_seek_seconds(ma_data_source*pDataSource,float secondCount,float*pSecondsSeeked)
{
M6 frameCount;
M6 framesSeeked=0;
M3 sampleRate;
Me Mf;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_data_source_get_data_format(pDataSource,NULL,NULL,&sampleRate,NULL,0);
if (Mf !=Ms) {
Mr Mf;
}
frameCount=(M6)(secondCount*sampleRate);
Mf=ma_data_source_seek_pcm_frames(pDataSource,frameCount,&framesSeeked);
*pSecondsSeeked=(ma_int64)framesSeeked / (float)sampleRate;
Mr Mf;
}
MA_API Me ma_data_source_seek_to_second(ma_data_source*pDataSource,float seekPointInSeconds)
{
M6 frameIndex;
M3 sampleRate;
Me Mf;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
Mf=ma_data_source_get_data_format(pDataSource,NULL,NULL,&sampleRate,NULL,0);
if (Mf !=Ms) {
Mr Mf;
}
frameIndex=(M6)(seekPointInSeconds*sampleRate);
Mr ma_data_source_seek_to_pcm_frame(pDataSource,frameIndex);
}
MA_API Me ma_data_source_get_data_format(ma_data_source*pDataSource,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
Me Mf;
ma_format format;
M3 Mh;
M3 sampleRate;
if (pFormat !=NULL) {
*pFormat=ma_format_unknown;
}
if (pChannels !=NULL) {
*pChannels=0;
}
if (pSampleRate !=NULL) {
*pSampleRate=0;
}
if (pChannelMap !=NULL) {
MA_ZERO_MEMORY(pChannelMap,sizeof(*pChannelMap)*channelMapCap);
}
if (pDataSourceBase==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(pDataSourceBase->vtable !=NULL);
if (pDataSourceBase->vtable->onGetDataFormat==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mf=pDataSourceBase->vtable->onGetDataFormat(pDataSource,&format,&Mh,&sampleRate,pChannelMap,channelMapCap);
if (Mf !=Ms) {
Mr Mf;
}
if (pFormat !=NULL) {
*pFormat=format;
}
if (pChannels !=NULL) {
*pChannels=Mh;
}
if (pSampleRate !=NULL) {
*pSampleRate=sampleRate;
}
Mr Ms;
}
MA_API Me ma_data_source_get_cursor_in_pcm_frames(ma_data_source*pDataSource,M6*pCursor)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
Me Mf;
M6 cursor;
if (pCursor==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=0;
if (pDataSourceBase==NULL) {
Mr Ms;
}
MA_ASSERT(pDataSourceBase->vtable !=NULL);
if (pDataSourceBase->vtable->onGetCursor==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mf=pDataSourceBase->vtable->onGetCursor(pDataSourceBase,&cursor);
if (Mf !=Ms) {
Mr Mf;
}
if (cursor<pDataSourceBase->rangeBegInFrames) {
*pCursor=0;
} else {
*pCursor=cursor-pDataSourceBase->rangeBegInFrames;
}
Mr Ms;
}
MA_API Me ma_data_source_get_length_in_pcm_frames(ma_data_source*pDataSource,M6*pLength)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pLength==NULL) {
Mr MA_INVALID_ARGS;
}
*pLength=0;
if (pDataSourceBase==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ASSERT(pDataSourceBase->vtable !=NULL);
if (pDataSourceBase->rangeEndInFrames !=~((M6)0)) {
*pLength=pDataSourceBase->rangeEndInFrames-pDataSourceBase->rangeBegInFrames;
Mr Ms;
}
if (pDataSourceBase->vtable->onGetLength==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pDataSourceBase->vtable->onGetLength(pDataSource,pLength);
}
MA_API Me ma_data_source_get_cursor_in_seconds(ma_data_source*pDataSource,float*pCursor)
{
Me Mf;
M6 cursorInPCMFrames;
M3 sampleRate;
if (pCursor==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=0;
Mf=ma_data_source_get_cursor_in_pcm_frames(pDataSource,&cursorInPCMFrames);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_data_source_get_data_format(pDataSource,NULL,NULL,&sampleRate,NULL,0);
if (Mf !=Ms) {
Mr Mf;
}
*pCursor=(ma_int64)cursorInPCMFrames / (float)sampleRate;
Mr Ms;
}
MA_API Me ma_data_source_get_length_in_seconds(ma_data_source*pDataSource,float*pLength)
{
Me Mf;
M6 lengthInPCMFrames;
M3 sampleRate;
if (pLength==NULL) {
Mr MA_INVALID_ARGS;
}
*pLength=0;
Mf=ma_data_source_get_length_in_pcm_frames(pDataSource,&lengthInPCMFrames);
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_data_source_get_data_format(pDataSource,NULL,NULL,&sampleRate,NULL,0);
if (Mf !=Ms) {
Mr Mf;
}
*pLength=(ma_int64)lengthInPCMFrames / (float)sampleRate;
Mr Ms;
}
MA_API Me ma_data_source_set_looping(ma_data_source*pDataSource,ma_bool32 isLooping)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
ma_atomic_exchange_32(&pDataSourceBase->isLooping,isLooping);
MA_ASSERT(pDataSourceBase->vtable !=NULL);
if (pDataSourceBase->vtable->onSetLooping==NULL) {
Mr Ms;
}
Mr pDataSourceBase->vtable->onSetLooping(pDataSource,isLooping);
}
MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source*pDataSource)
{
const ma_data_source_base*pDataSourceBase=(const ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_FALSE;
}
Mr ma_atomic_load_32(&pDataSourceBase->isLooping);
}
MA_API Me ma_data_source_set_range_in_pcm_frames(ma_data_source*pDataSource,M6 rangeBegInFrames,M6 rangeEndInFrames)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
Me Mf;
M6 relativeCursor;
M6 absoluteCursor;
ma_bool32 doSeekAdjustment=MA_FALSE;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
if (rangeEndInFrames<rangeBegInFrames) {
Mr MA_INVALID_ARGS;
}
Mf=ma_data_source_get_cursor_in_pcm_frames(pDataSource,&relativeCursor);
if (Mf==Ms) {
doSeekAdjustment=MA_TRUE;
absoluteCursor=relativeCursor+pDataSourceBase->rangeBegInFrames;
} else {
doSeekAdjustment=MA_FALSE;
relativeCursor=0;
absoluteCursor=0;
}
pDataSourceBase->rangeBegInFrames=rangeBegInFrames;
pDataSourceBase->rangeEndInFrames=rangeEndInFrames;
pDataSourceBase->loopBegInFrames=0;
pDataSourceBase->loopEndInFrames=~((M6)0);
if (doSeekAdjustment) {
if (absoluteCursor<rangeBegInFrames) {
ma_data_source_seek_to_pcm_frame(pDataSource,0);
} else if (absoluteCursor>rangeEndInFrames) {
ma_data_source_seek_to_pcm_frame(pDataSource,rangeEndInFrames-rangeBegInFrames);
}
}
Mr Ms;
}
MA_API Mv ma_data_source_get_range_in_pcm_frames(const ma_data_source*pDataSource,M6*pRangeBegInFrames,M6*pRangeEndInFrames)
{
const ma_data_source_base*pDataSourceBase=(const ma_data_source_base*)pDataSource;
if (pRangeBegInFrames !=NULL) {
*pRangeBegInFrames=0;
}
if (pRangeEndInFrames !=NULL) {
*pRangeEndInFrames=0;
}
if (pDataSource==NULL) {
Mr;
}
if (pRangeBegInFrames !=NULL) {
*pRangeBegInFrames=pDataSourceBase->rangeBegInFrames;
}
if (pRangeEndInFrames !=NULL) {
*pRangeEndInFrames=pDataSourceBase->rangeEndInFrames;
}
}
MA_API Me ma_data_source_set_loop_point_in_pcm_frames(ma_data_source*pDataSource,M6 loopBegInFrames,M6 loopEndInFrames)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
if (loopEndInFrames<loopBegInFrames) {
Mr MA_INVALID_ARGS;
}
if (loopEndInFrames>pDataSourceBase->rangeEndInFrames&&loopEndInFrames !=~((M6)0)) {
Mr MA_INVALID_ARGS;
}
pDataSourceBase->loopBegInFrames=loopBegInFrames;
pDataSourceBase->loopEndInFrames=loopEndInFrames;
if (pDataSourceBase->loopEndInFrames>(pDataSourceBase->rangeEndInFrames-pDataSourceBase->rangeBegInFrames)&&pDataSourceBase->loopEndInFrames !=~((M6)0)) {
pDataSourceBase->loopEndInFrames=(pDataSourceBase->rangeEndInFrames-pDataSourceBase->rangeBegInFrames);
}
Mr Ms;
}
MA_API Mv ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source*pDataSource,M6*pLoopBegInFrames,M6*pLoopEndInFrames)
{
const ma_data_source_base*pDataSourceBase=(const ma_data_source_base*)pDataSource;
if (pLoopBegInFrames !=NULL) {
*pLoopBegInFrames=0;
}
if (pLoopEndInFrames !=NULL) {
*pLoopEndInFrames=0;
}
if (pDataSource==NULL) {
Mr;
}
if (pLoopBegInFrames !=NULL) {
*pLoopBegInFrames=pDataSourceBase->loopBegInFrames;
}
if (pLoopEndInFrames !=NULL) {
*pLoopEndInFrames=pDataSourceBase->loopEndInFrames;
}
}
MA_API Me ma_data_source_set_current(ma_data_source*pDataSource,ma_data_source*pCurrentDataSource)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
pDataSourceBase->pCurrent=pCurrentDataSource;
Mr Ms;
}
MA_API ma_data_source*ma_data_source_get_current(const ma_data_source*pDataSource)
{
const ma_data_source_base*pDataSourceBase=(const ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr NULL;
}
Mr pDataSourceBase->pCurrent;
}
MA_API Me ma_data_source_set_next(ma_data_source*pDataSource,ma_data_source*pNextDataSource)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
pDataSourceBase->pNext=pNextDataSource;
Mr Ms;
}
MA_API ma_data_source*ma_data_source_get_next(const ma_data_source*pDataSource)
{
const ma_data_source_base*pDataSourceBase=(const ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr NULL;
}
Mr pDataSourceBase->pNext;
}
MA_API Me ma_data_source_set_next_callback(ma_data_source*pDataSource,ma_data_source_get_next_proc onGetNext)
{
ma_data_source_base*pDataSourceBase=(ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr MA_INVALID_ARGS;
}
pDataSourceBase->onGetNext=onGetNext;
Mr Ms;
}
MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source*pDataSource)
{
const ma_data_source_base*pDataSourceBase=(const ma_data_source_base*)pDataSource;
if (pDataSource==NULL) {
Mr NULL;
}
Mr pDataSourceBase->onGetNext;
}
static Me ma_audio_buffer_ref__data_source_on_read(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
ma_audio_buffer_ref*pAudioBufferRef=(ma_audio_buffer_ref*)pDataSource;
M6 framesRead=ma_audio_buffer_ref_read_pcm_frames(pAudioBufferRef,pFramesOut,frameCount,MA_FALSE);
if (pFramesRead !=NULL) {
*pFramesRead=framesRead;
}
if (framesRead<frameCount||framesRead==0) {
Mr MA_AT_END;
}
Mr Ms;
}
static Me ma_audio_buffer_ref__data_source_on_seek(ma_data_source*pDataSource,M6 frameIndex)
{
Mr ma_audio_buffer_ref_seek_to_pcm_frame((ma_audio_buffer_ref*)pDataSource,frameIndex);
}
static Me ma_audio_buffer_ref__data_source_on_get_data_format(ma_data_source*pDataSource,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap)
{
ma_audio_buffer_ref*pAudioBufferRef=(ma_audio_buffer_ref*)pDataSource;
*pFormat=pAudioBufferRef->format;
*pChannels=pAudioBufferRef->Mh;
*pSampleRate=pAudioBufferRef->sampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,pAudioBufferRef->Mh);
Mr Ms;
}
static Me ma_audio_buffer_ref__data_source_on_get_cursor(ma_data_source*pDataSource,M6*pCursor)
{
ma_audio_buffer_ref*pAudioBufferRef=(ma_audio_buffer_ref*)pDataSource;
*pCursor=pAudioBufferRef->cursor;
Mr Ms;
}
static Me ma_audio_buffer_ref__data_source_on_get_length(ma_data_source*pDataSource,M6*pLength)
{
ma_audio_buffer_ref*pAudioBufferRef=(ma_audio_buffer_ref*)pDataSource;
*pLength=pAudioBufferRef->sizeInFrames;
Mr Ms;
}
static ma_data_source_vtable g_ma_audio_buffer_ref_data_source_vtable=
{
ma_audio_buffer_ref__data_source_on_read,ma_audio_buffer_ref__data_source_on_seek,ma_audio_buffer_ref__data_source_on_get_data_format,ma_audio_buffer_ref__data_source_on_get_cursor,ma_audio_buffer_ref__data_source_on_get_length,NULL,0
};
MA_API Me ma_audio_buffer_ref_init(ma_format format,M3 Mh,const Mv*pData,M6 sizeInFrames,ma_audio_buffer_ref*pAudioBufferRef)
{
Me Mf;
ma_data_source_config dataSourceConfig;
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pAudioBufferRef);
dataSourceConfig=ma_data_source_config_init();
dataSourceConfig.vtable=&g_ma_audio_buffer_ref_data_source_vtable;
Mf=ma_data_source_init(&dataSourceConfig,&pAudioBufferRef->ds);
if (Mf !=Ms) {
Mr Mf;
}
pAudioBufferRef->format=format;
pAudioBufferRef->Mh=Mh;
pAudioBufferRef->sampleRate=0;
pAudioBufferRef->cursor=0;
pAudioBufferRef->sizeInFrames=sizeInFrames;
pAudioBufferRef->pData=pData;
Mr Ms;
}
MA_API Mv ma_audio_buffer_ref_uninit(ma_audio_buffer_ref*pAudioBufferRef)
{
if (pAudioBufferRef==NULL) {
Mr;
}
ma_data_source_uninit(&pAudioBufferRef->ds);
}
MA_API Me ma_audio_buffer_ref_set_data(ma_audio_buffer_ref*pAudioBufferRef,const Mv*pData,M6 sizeInFrames)
{
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
pAudioBufferRef->cursor=0;
pAudioBufferRef->sizeInFrames=sizeInFrames;
pAudioBufferRef->pData=pData;
Mr Ms;
}
MA_API M6 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref*pAudioBufferRef,Mv*pFramesOut,M6 frameCount,ma_bool32 loop)
{
M6 totalFramesRead=0;
if (pAudioBufferRef==NULL) {
Mr 0;
}
if (frameCount==0) {
Mr 0;
}
while (totalFramesRead<frameCount) {
M6 framesAvailable=pAudioBufferRef->sizeInFrames-pAudioBufferRef->cursor;
M6 framesRemaining=frameCount-totalFramesRead;
M6 framesToRead;
framesToRead=framesRemaining;
if (framesToRead>framesAvailable) {
framesToRead=framesAvailable;
}
if (pFramesOut !=NULL) {
ma_copy_pcm_frames(ma_offset_ptr(pFramesOut,totalFramesRead*ma_get_bytes_per_frame(pAudioBufferRef->format,pAudioBufferRef->Mh)),ma_offset_ptr(pAudioBufferRef->pData,pAudioBufferRef->cursor*ma_get_bytes_per_frame(pAudioBufferRef->format,pAudioBufferRef->Mh)),framesToRead,pAudioBufferRef->format,pAudioBufferRef->Mh);
}
totalFramesRead+=framesToRead;
pAudioBufferRef->cursor+=framesToRead;
if (pAudioBufferRef->cursor==pAudioBufferRef->sizeInFrames) {
if (loop) {
pAudioBufferRef->cursor=0;
} else {
break;
}
}
MA_ASSERT(pAudioBufferRef->cursor<pAudioBufferRef->sizeInFrames);
}
Mr totalFramesRead;
}
MA_API Me ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref*pAudioBufferRef,M6 frameIndex)
{
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
if (frameIndex>pAudioBufferRef->sizeInFrames) {
Mr MA_INVALID_ARGS;
}
pAudioBufferRef->cursor=(size_t)frameIndex;
Mr Ms;
}
MA_API Me ma_audio_buffer_ref_map(ma_audio_buffer_ref*pAudioBufferRef,Mv**ppFramesOut,M6*pFrameCount)
{
M6 framesAvailable;
M6 frameCount=0;
if (ppFramesOut !=NULL) {
*ppFramesOut=NULL;
}
if (pFrameCount !=NULL) {
frameCount=*pFrameCount;
*pFrameCount=0;
}
if (pAudioBufferRef==NULL||ppFramesOut==NULL||pFrameCount==NULL) {
Mr MA_INVALID_ARGS;
}
framesAvailable=pAudioBufferRef->sizeInFrames-pAudioBufferRef->cursor;
if (frameCount>framesAvailable) {
frameCount=framesAvailable;
}
*ppFramesOut=ma_offset_ptr(pAudioBufferRef->pData,pAudioBufferRef->cursor*ma_get_bytes_per_frame(pAudioBufferRef->format,pAudioBufferRef->Mh));
*pFrameCount=frameCount;
Mr Ms;
}
MA_API Me ma_audio_buffer_ref_unmap(ma_audio_buffer_ref*pAudioBufferRef,M6 frameCount)
{
M6 framesAvailable;
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
framesAvailable=pAudioBufferRef->sizeInFrames-pAudioBufferRef->cursor;
if (frameCount>framesAvailable) {
Mr MA_INVALID_ARGS;
}
pAudioBufferRef->cursor+=frameCount;
if (pAudioBufferRef->cursor==pAudioBufferRef->sizeInFrames) {
Mr MA_AT_END;
} else {
Mr Ms;
}
}
MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref*pAudioBufferRef)
{
if (pAudioBufferRef==NULL) {
Mr MA_FALSE;
}
Mr pAudioBufferRef->cursor==pAudioBufferRef->sizeInFrames;
}
MA_API Me ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref*pAudioBufferRef,M6*pCursor)
{
if (pCursor==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=0;
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=pAudioBufferRef->cursor;
Mr Ms;
}
MA_API Me ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref*pAudioBufferRef,M6*pLength)
{
if (pLength==NULL) {
Mr MA_INVALID_ARGS;
}
*pLength=0;
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
*pLength=pAudioBufferRef->sizeInFrames;
Mr Ms;
}
MA_API Me ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref*pAudioBufferRef,M6*pAvailableFrames)
{
if (pAvailableFrames==NULL) {
Mr MA_INVALID_ARGS;
}
*pAvailableFrames=0;
if (pAudioBufferRef==NULL) {
Mr MA_INVALID_ARGS;
}
if (pAudioBufferRef->sizeInFrames<=pAudioBufferRef->cursor) {
*pAvailableFrames=0;
} else {
*pAvailableFrames=pAudioBufferRef->sizeInFrames-pAudioBufferRef->cursor;
}
Mr Ms;
}
MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format,M3 Mh,M6 sizeInFrames,const Mv*pData,const ma_allocation_callbacks*pAllocationCallbacks)
{
ma_audio_buffer_config config;
MA_ZERO_OBJECT(&config);
config.format=format;
config.Mh=Mh;
config.sampleRate=0;
config.sizeInFrames=sizeInFrames;
config.pData=pData;
ma_allocation_callbacks_init_copy(&config.allocationCallbacks,pAllocationCallbacks);
Mr config;
}
static Me ma_audio_buffer_init_ex(const ma_audio_buffer_config*Mo,ma_bool32 doCopy,ma_audio_buffer*pAudioBuffer)
{
Me Mf;
if (pAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_MEMORY(pAudioBuffer,sizeof(*pAudioBuffer)-sizeof(pAudioBuffer->_pExtraData));
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->sizeInFrames==0) {
Mr MA_INVALID_ARGS;
}
Mf=ma_audio_buffer_ref_init(Mo->format,Mo->Mh,NULL,0,&pAudioBuffer->ref);
if (Mf !=Ms) {
Mr Mf;
}
pAudioBuffer->ref.sampleRate=Mo->sampleRate;
ma_allocation_callbacks_init_copy(&pAudioBuffer->allocationCallbacks,&Mo->allocationCallbacks);
if (doCopy) {
M6 allocationSizeInBytes;
Mv*pData;
allocationSizeInBytes=Mo->sizeInFrames*ma_get_bytes_per_frame(Mo->format,Mo->Mh);
if (allocationSizeInBytes>MA_SIZE_MAX) {
Mr MA_OUT_OF_MEMORY;
}
pData=ma_malloc((size_t)allocationSizeInBytes,&pAudioBuffer->allocationCallbacks);
if (pData==NULL) {
Mr MA_OUT_OF_MEMORY;
}
if (Mo->pData !=NULL) {
ma_copy_pcm_frames(pData,Mo->pData,Mo->sizeInFrames,Mo->format,Mo->Mh);
} else {
ma_silence_pcm_frames(pData,Mo->sizeInFrames,Mo->format,Mo->Mh);
}
ma_audio_buffer_ref_set_data(&pAudioBuffer->ref,pData,Mo->sizeInFrames);
pAudioBuffer->ownsData=MA_TRUE;
} else {
ma_audio_buffer_ref_set_data(&pAudioBuffer->ref,Mo->pData,Mo->sizeInFrames);
pAudioBuffer->ownsData=MA_FALSE;
}
Mr Ms;
}
static Mv ma_audio_buffer_uninit_ex(ma_audio_buffer*pAudioBuffer,ma_bool32 doFree)
{
if (pAudioBuffer==NULL) {
Mr;
}
if (pAudioBuffer->ownsData&&pAudioBuffer->ref.pData !=&pAudioBuffer->_pExtraData[0]) {
ma_free((Mv*)pAudioBuffer->ref.pData,&pAudioBuffer->allocationCallbacks);
}
if (doFree) {
ma_free(pAudioBuffer,&pAudioBuffer->allocationCallbacks);
}
ma_audio_buffer_ref_uninit(&pAudioBuffer->ref);
}
MA_API Me ma_audio_buffer_init(const ma_audio_buffer_config*Mo,ma_audio_buffer*pAudioBuffer)
{
Mr ma_audio_buffer_init_ex(Mo,MA_FALSE,pAudioBuffer);
}
MA_API Me ma_audio_buffer_init_copy(const ma_audio_buffer_config*Mo,ma_audio_buffer*pAudioBuffer)
{
Mr ma_audio_buffer_init_ex(Mo,MA_TRUE,pAudioBuffer);
}
MA_API Me ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config*Mo,ma_audio_buffer**ppAudioBuffer)
{
Me Mf;
ma_audio_buffer*pAudioBuffer;
ma_audio_buffer_config innerConfig;
M6 allocationSizeInBytes;
if (ppAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
*ppAudioBuffer=NULL;
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
innerConfig=*Mo;
ma_allocation_callbacks_init_copy(&innerConfig.allocationCallbacks,&Mo->allocationCallbacks);
allocationSizeInBytes=sizeof(*pAudioBuffer)-sizeof(pAudioBuffer->_pExtraData)+(Mo->sizeInFrames*ma_get_bytes_per_frame(Mo->format,Mo->Mh));
if (allocationSizeInBytes>MA_SIZE_MAX) {
Mr MA_OUT_OF_MEMORY;
}
pAudioBuffer=(ma_audio_buffer*)ma_malloc((size_t)allocationSizeInBytes,&innerConfig.allocationCallbacks);
if (pAudioBuffer==NULL) {
Mr MA_OUT_OF_MEMORY;
}
if (Mo->pData !=NULL) {
ma_copy_pcm_frames(&pAudioBuffer->_pExtraData[0],Mo->pData,Mo->sizeInFrames,Mo->format,Mo->Mh);
} else {
ma_silence_pcm_frames(&pAudioBuffer->_pExtraData[0],Mo->sizeInFrames,Mo->format,Mo->Mh);
}
innerConfig.pData=&pAudioBuffer->_pExtraData[0];
Mf=ma_audio_buffer_init_ex(&innerConfig,MA_FALSE,pAudioBuffer);
if (Mf !=Ms) {
ma_free(pAudioBuffer,&innerConfig.allocationCallbacks);
Mr Mf;
}
*ppAudioBuffer=pAudioBuffer;
Mr Ms;
}
MA_API Mv ma_audio_buffer_uninit(ma_audio_buffer*pAudioBuffer)
{
ma_audio_buffer_uninit_ex(pAudioBuffer,MA_FALSE);
}
MA_API Mv ma_audio_buffer_uninit_and_free(ma_audio_buffer*pAudioBuffer)
{
ma_audio_buffer_uninit_ex(pAudioBuffer,MA_TRUE);
}
MA_API M6 ma_audio_buffer_read_pcm_frames(ma_audio_buffer*pAudioBuffer,Mv*pFramesOut,M6 frameCount,ma_bool32 loop)
{
if (pAudioBuffer==NULL) {
Mr 0;
}
Mr ma_audio_buffer_ref_read_pcm_frames(&pAudioBuffer->ref,pFramesOut,frameCount,loop);
}
MA_API Me ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer*pAudioBuffer,M6 frameIndex)
{
if (pAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_audio_buffer_ref_seek_to_pcm_frame(&pAudioBuffer->ref,frameIndex);
}
MA_API Me ma_audio_buffer_map(ma_audio_buffer*pAudioBuffer,Mv**ppFramesOut,M6*pFrameCount)
{
if (ppFramesOut !=NULL) {
*ppFramesOut=NULL;
}
if (pAudioBuffer==NULL) {
if (pFrameCount !=NULL) {
*pFrameCount=0;
}
Mr MA_INVALID_ARGS;
}
Mr ma_audio_buffer_ref_map(&pAudioBuffer->ref,ppFramesOut,pFrameCount);
}
MA_API Me ma_audio_buffer_unmap(ma_audio_buffer*pAudioBuffer,M6 frameCount)
{
if (pAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_audio_buffer_ref_unmap(&pAudioBuffer->ref,frameCount);
}
MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer*pAudioBuffer)
{
if (pAudioBuffer==NULL) {
Mr MA_FALSE;
}
Mr ma_audio_buffer_ref_at_end(&pAudioBuffer->ref);
}
MA_API Me ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer*pAudioBuffer,M6*pCursor)
{
if (pAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_audio_buffer_ref_get_cursor_in_pcm_frames(&pAudioBuffer->ref,pCursor);
}
MA_API Me ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer*pAudioBuffer,M6*pLength)
{
if (pAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_audio_buffer_ref_get_length_in_pcm_frames(&pAudioBuffer->ref,pLength);
}
MA_API Me ma_audio_buffer_get_available_frames(const ma_audio_buffer*pAudioBuffer,M6*pAvailableFrames)
{
if (pAvailableFrames==NULL) {
Mr MA_INVALID_ARGS;
}
*pAvailableFrames=0;
if (pAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
Mr ma_audio_buffer_ref_get_available_frames(&pAudioBuffer->ref,pAvailableFrames);
}
MA_API Me ma_paged_audio_buffer_data_init(ma_format format,M3 Mh,ma_paged_audio_buffer_data*pData)
{
if (pData==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pData);
pData->format=format;
pData->Mh=Mh;
pData->pTail=&pData->head;
Mr Ms;
}
MA_API Mv ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data*pData,const ma_allocation_callbacks*pAllocationCallbacks)
{
ma_paged_audio_buffer_page*pPage;
if (pData==NULL) {
Mr;
}
pPage=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pData->head.pNext);
while (pPage !=NULL) {
ma_paged_audio_buffer_page*pNext=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPage->pNext);
ma_free(pPage,pAllocationCallbacks);
pPage=pNext;
}
}
MA_API ma_paged_audio_buffer_page*ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data*pData)
{
if (pData==NULL) {
Mr NULL;
}
Mr&pData->head;
}
MA_API ma_paged_audio_buffer_page*ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data*pData)
{
if (pData==NULL) {
Mr NULL;
}
Mr pData->pTail;
}
MA_API Me ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data*pData,M6*pLength)
{
ma_paged_audio_buffer_page*pPage;
if (pLength==NULL) {
Mr MA_INVALID_ARGS;
}
*pLength=0;
if (pData==NULL) {
Mr MA_INVALID_ARGS;
}
for (pPage=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pData->head.pNext); pPage !=NULL; pPage=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPage->pNext)) {
*pLength+=pPage->sizeInFrames;
}
Mr Ms;
}
MA_API Me ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data*pData,M6 pageSizeInFrames,const Mv*pInitialData,const ma_allocation_callbacks*pAllocationCallbacks,ma_paged_audio_buffer_page**ppPage)
{
ma_paged_audio_buffer_page*pPage;
M6 allocationSize;
if (ppPage==NULL) {
Mr MA_INVALID_ARGS;
}
*ppPage=NULL;
if (pData==NULL) {
Mr MA_INVALID_ARGS;
}
allocationSize=sizeof(*pPage)+(pageSizeInFrames*ma_get_bytes_per_frame(pData->format,pData->Mh));
if (allocationSize>MA_SIZE_MAX) {
Mr MA_OUT_OF_MEMORY;
}
pPage=(ma_paged_audio_buffer_page*)ma_malloc((size_t)allocationSize,pAllocationCallbacks);
if (pPage==NULL) {
Mr MA_OUT_OF_MEMORY;
}
pPage->pNext=NULL;
pPage->sizeInFrames=pageSizeInFrames;
if (pInitialData !=NULL) {
ma_copy_pcm_frames(pPage->pAudioData,pInitialData,pageSizeInFrames,pData->format,pData->Mh);
}
*ppPage=pPage;
Mr Ms;
}
MA_API Me ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data*pData,ma_paged_audio_buffer_page*pPage,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pData==NULL||pPage==NULL) {
Mr MA_INVALID_ARGS;
}
ma_free(pPage,pAllocationCallbacks);
Mr Ms;
}
MA_API Me ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data*pData,ma_paged_audio_buffer_page*pPage)
{
if (pData==NULL||pPage==NULL) {
Mr MA_INVALID_ARGS;
}
for (;;) {
ma_paged_audio_buffer_page*pOldTail=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pData->pTail);
ma_paged_audio_buffer_page*pNewTail=pPage;
if (ma_atomic_compare_exchange_weak_ptr((volatile Mv**)&pData->pTail,(Mv**)&pOldTail,pNewTail)) {
ma_atomic_exchange_ptr(&pOldTail->pNext,pPage);
break;
}
}
Mr Ms;
}
MA_API Me ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data*pData,M3 pageSizeInFrames,const Mv*pInitialData,const ma_allocation_callbacks*pAllocationCallbacks)
{
Me Mf;
ma_paged_audio_buffer_page*pPage;
Mf=ma_paged_audio_buffer_data_allocate_page(pData,pageSizeInFrames,pInitialData,pAllocationCallbacks,&pPage);
if (Mf !=Ms) {
Mr Mf;
}
Mr ma_paged_audio_buffer_data_append_page(pData,pPage);
}
MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data*pData)
{
ma_paged_audio_buffer_config config;
MA_ZERO_OBJECT(&config);
config.pData=pData;
Mr config;
}
static Me ma_paged_audio_buffer__data_source_on_read(ma_data_source*pDataSource,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
Mr ma_paged_audio_buffer_read_pcm_frames((ma_paged_audio_buffer*)pDataSource,pFramesOut,frameCount,pFramesRead);
}
static Me ma_paged_audio_buffer__data_source_on_seek(ma_data_source*pDataSource,M6 frameIndex)
{
Mr ma_paged_audio_buffer_seek_to_pcm_frame((ma_paged_audio_buffer*)pDataSource,frameIndex);
}
static Me ma_paged_audio_buffer__data_source_on_get_data_format(ma_data_source*pDataSource,ma_format*pFormat,M3*pChannels,M3*pSampleRate,ma_channel*pChannelMap,size_t channelMapCap)
{
ma_paged_audio_buffer*pPagedAudioBuffer=(ma_paged_audio_buffer*)pDataSource;
*pFormat=pPagedAudioBuffer->pData->format;
*pChannels=pPagedAudioBuffer->pData->Mh;
*pSampleRate=0;
ma_channel_map_init_standard(ma_standard_channel_map_default,pChannelMap,channelMapCap,pPagedAudioBuffer->pData->Mh);
Mr Ms;
}
static Me ma_paged_audio_buffer__data_source_on_get_cursor(ma_data_source*pDataSource,M6*pCursor)
{
Mr ma_paged_audio_buffer_get_cursor_in_pcm_frames((ma_paged_audio_buffer*)pDataSource,pCursor);
}
static Me ma_paged_audio_buffer__data_source_on_get_length(ma_data_source*pDataSource,M6*pLength)
{
Mr ma_paged_audio_buffer_get_length_in_pcm_frames((ma_paged_audio_buffer*)pDataSource,pLength);
}
static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable=
{
ma_paged_audio_buffer__data_source_on_read,ma_paged_audio_buffer__data_source_on_seek,ma_paged_audio_buffer__data_source_on_get_data_format,ma_paged_audio_buffer__data_source_on_get_cursor,ma_paged_audio_buffer__data_source_on_get_length,NULL,0
};
MA_API Me ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config*Mo,ma_paged_audio_buffer*pPagedAudioBuffer)
{
Me Mf;
ma_data_source_config dataSourceConfig;
if (pPagedAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pPagedAudioBuffer);
if (Mo==NULL) {
Mr MA_INVALID_ARGS;
}
if (Mo->pData==NULL) {
Mr MA_INVALID_ARGS;
}
dataSourceConfig=ma_data_source_config_init();
dataSourceConfig.vtable=&g_ma_paged_audio_buffer_data_source_vtable;
Mf=ma_data_source_init(&dataSourceConfig,&pPagedAudioBuffer->ds);
if (Mf !=Ms) {
Mr Mf;
}
pPagedAudioBuffer->pData=Mo->pData;
pPagedAudioBuffer->pCurrent=ma_paged_audio_buffer_data_get_head(Mo->pData);
pPagedAudioBuffer->relativeCursor=0;
pPagedAudioBuffer->absoluteCursor=0;
Mr Ms;
}
MA_API Mv ma_paged_audio_buffer_uninit(ma_paged_audio_buffer*pPagedAudioBuffer)
{
if (pPagedAudioBuffer==NULL) {
Mr;
}
}
MA_API Me ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer*pPagedAudioBuffer,Mv*pFramesOut,M6 frameCount,M6*pFramesRead)
{
Me Mf=Ms;
M6 totalFramesRead=0;
ma_format format;
M3 Mh;
if (pPagedAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
format=pPagedAudioBuffer->pData->format;
Mh=pPagedAudioBuffer->pData->Mh;
while (totalFramesRead<frameCount) {
M6 framesRemainingInCurrentPage;
M6 framesRemainingToRead=frameCount-totalFramesRead;
M6 framesToReadThisIteration;
MA_ASSERT(pPagedAudioBuffer->pCurrent !=NULL);
framesRemainingInCurrentPage=pPagedAudioBuffer->pCurrent->sizeInFrames-pPagedAudioBuffer->relativeCursor;
framesToReadThisIteration=ma_min(framesRemainingInCurrentPage,framesRemainingToRead);
ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut,totalFramesRead,format,Mh),ma_offset_pcm_frames_ptr(pPagedAudioBuffer->pCurrent->pAudioData,pPagedAudioBuffer->relativeCursor,format,Mh),framesToReadThisIteration,format,Mh);
totalFramesRead+=framesToReadThisIteration;
pPagedAudioBuffer->absoluteCursor+=framesToReadThisIteration;
pPagedAudioBuffer->relativeCursor+=framesToReadThisIteration;
MA_ASSERT(pPagedAudioBuffer->relativeCursor<=pPagedAudioBuffer->pCurrent->sizeInFrames);
if (pPagedAudioBuffer->relativeCursor==pPagedAudioBuffer->pCurrent->sizeInFrames) {
ma_paged_audio_buffer_page*pNext=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPagedAudioBuffer->pCurrent->pNext);
if (pNext==NULL) {
Mf=MA_AT_END;
break;
} else {
pPagedAudioBuffer->pCurrent=pNext;
pPagedAudioBuffer->relativeCursor=0;
}
}
}
if (pFramesRead !=NULL) {
*pFramesRead=totalFramesRead;
}
Mr Mf;
}
MA_API Me ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer*pPagedAudioBuffer,M6 frameIndex)
{
if (pPagedAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
if (frameIndex==pPagedAudioBuffer->absoluteCursor) {
Mr Ms;
}
if (frameIndex<pPagedAudioBuffer->absoluteCursor) {
pPagedAudioBuffer->pCurrent=ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData);
pPagedAudioBuffer->absoluteCursor=0;
pPagedAudioBuffer->relativeCursor=0;
}
if (frameIndex>pPagedAudioBuffer->absoluteCursor) {
ma_paged_audio_buffer_page*pPage;
M6 runningCursor=0;
for (pPage=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData)->pNext); pPage !=NULL; pPage=(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(&pPage->pNext)) {
M6 pageRangeBeg=runningCursor;
M6 pageRangeEnd=pageRangeBeg+pPage->sizeInFrames;
if (frameIndex>=pageRangeBeg) {
if (frameIndex<pageRangeEnd||(frameIndex==pageRangeEnd&&pPage==(ma_paged_audio_buffer_page*)ma_atomic_load_ptr(ma_paged_audio_buffer_data_get_tail(pPagedAudioBuffer->pData)))) {
 pPagedAudioBuffer->pCurrent=pPage;
 pPagedAudioBuffer->absoluteCursor=frameIndex;
 pPagedAudioBuffer->relativeCursor=frameIndex-pageRangeBeg;
 Mr Ms;
}
}
runningCursor=pageRangeEnd;
}
Mr MA_BAD_SEEK;
}
Mr Ms;
}
MA_API Me ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer*pPagedAudioBuffer,M6*pCursor)
{
if (pCursor==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=0;
if (pPagedAudioBuffer==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=pPagedAudioBuffer->absoluteCursor;
Mr Ms;
}
MA_API Me ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer*pPagedAudioBuffer,M6*pLength)
{
Mr ma_paged_audio_buffer_data_get_length_in_pcm_frames(pPagedAudioBuffer->pData,pLength);
}
MA_API Me ma_vfs_open(ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pFile==NULL) {
Mr MA_INVALID_ARGS;
}
*pFile=NULL;
if (pVFS==NULL||pFilePath==NULL||openMode==0) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onOpen==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onOpen(pVFS,pFilePath,openMode,pFile);
}
MA_API Me ma_vfs_open_w(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pFile==NULL) {
Mr MA_INVALID_ARGS;
}
*pFile=NULL;
if (pVFS==NULL||pFilePath==NULL||openMode==0) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onOpenW==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onOpenW(pVFS,pFilePath,openMode,pFile);
}
MA_API Me ma_vfs_close(ma_vfs*pVFS,ma_vfs_file file)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pVFS==NULL||file==NULL) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onClose==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onClose(pVFS,file);
}
MA_API Me ma_vfs_read(ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
Me Mf;
size_t bytesRead=0;
if (pBytesRead !=NULL) {
*pBytesRead=0;
}
if (pVFS==NULL||file==NULL||pDst==NULL) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onRead==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mf=pCallbacks->onRead(pVFS,file,pDst,sizeInBytes,&bytesRead);
if (pBytesRead !=NULL) {
*pBytesRead=bytesRead;
}
if (Mf==Ms&&bytesRead==0&&sizeInBytes>0) {
Mf=MA_AT_END;
}
Mr Mf;
}
MA_API Me ma_vfs_write(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pBytesWritten !=NULL) {
*pBytesWritten=0;
}
if (pVFS==NULL||file==NULL||pSrc==NULL) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onWrite==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onWrite(pVFS,file,pSrc,sizeInBytes,pBytesWritten);
}
MA_API Me ma_vfs_seek(ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pVFS==NULL||file==NULL) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onSeek==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onSeek(pVFS,file,offset,origin);
}
MA_API Me ma_vfs_tell(ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pCursor==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=0;
if (pVFS==NULL||file==NULL) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onTell==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onTell(pVFS,file,pCursor);
}
MA_API Me ma_vfs_info(ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo)
{
ma_vfs_callbacks*pCallbacks=(ma_vfs_callbacks*)pVFS;
if (pInfo==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pInfo);
if (pVFS==NULL||file==NULL) {
Mr MA_INVALID_ARGS;
}
if (pCallbacks->onInfo==NULL) {
Mr MA_NOT_IMPLEMENTED;
}
Mr pCallbacks->onInfo(pVFS,file,pInfo);
}
#if !defined(MA_USE_WIN32_FILEIO)&&(defined(MA_WIN32)&&defined(MA_WIN32_DESKTOP)&&!defined(MA_NO_WIN32_FILEIO)&&!defined(MA_POSIX))
#define MA_USE_WIN32_FILEIO
#endif
#if defined(MA_USE_WIN32_FILEIO)
typedef DWORD (__stdcall*ma_SetFilePointer_proc)(HANDLE hFile,LONG lDistanceToMove,LONG*lpDistanceToMoveHigh,DWORD dwMoveMethod);
typedef BOOL (__stdcall*ma_SetFilePointerEx_proc)(HANDLE hFile,LARGE_INTEGER liDistanceToMove,LARGE_INTEGER*lpNewFilePointer,DWORD dwMoveMethod);
static ma_handle hKernel32DLL=NULL;
static ma_SetFilePointer_proc ma_SetFilePointer=NULL;
static ma_SetFilePointerEx_proc ma_SetFilePointerEx=NULL;
static Mv ma_win32_fileio_init(Mv)
{
if (hKernel32DLL==NULL) {
hKernel32DLL = ma_dlopen(NULL, "kernel32.dll");
if (hKernel32DLL !=NULL) {
ma_SetFilePointer = (ma_SetFilePointer_proc) ma_dlsym(NULL, hKernel32DLL, "SetFilePointer");
ma_SetFilePointerEx = (ma_SetFilePointerEx_proc)ma_dlsym(NULL, hKernel32DLL, "SetFilePointerEx");
}
}
}
static Mv ma_default_vfs__get_open_settings_win32(M3 openMode,DWORD*pDesiredAccess,DWORD*pShareMode,DWORD*pCreationDisposition)
{
*pDesiredAccess=0;
if ((openMode&MA_OPEN_MODE_READ) !=0) {
*pDesiredAccess|=GENERIC_READ;
}
if ((openMode&MA_OPEN_MODE_WRITE) !=0) {
*pDesiredAccess|=GENERIC_WRITE;
}
*pShareMode=0;
if ((openMode&MA_OPEN_MODE_READ) !=0) {
*pShareMode|=FILE_SHARE_READ;
}
if ((openMode&MA_OPEN_MODE_WRITE) !=0) {
*pCreationDisposition=CREATE_ALWAYS;
} else {
*pCreationDisposition=OPEN_EXISTING;
}
}
static Me ma_default_vfs_open__win32(ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
HANDLE hFile;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
(Mv)pVFS;
ma_win32_fileio_init();
ma_default_vfs__get_open_settings_win32(openMode,&dwDesiredAccess,&dwShareMode,&dwCreationDisposition);
hFile=CreateFileA(pFilePath,dwDesiredAccess,dwShareMode,NULL,dwCreationDisposition,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile==INVALID_HANDLE_VALUE) {
Mr ma_result_from_GetLastError(GetLastError());
}
*pFile=hFile;
Mr Ms;
}
static Me ma_default_vfs_open_w__win32(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
HANDLE hFile;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
(Mv)pVFS;
ma_win32_fileio_init();
ma_default_vfs__get_open_settings_win32(openMode,&dwDesiredAccess,&dwShareMode,&dwCreationDisposition);
hFile=CreateFileW(pFilePath,dwDesiredAccess,dwShareMode,NULL,dwCreationDisposition,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile==INVALID_HANDLE_VALUE) {
Mr ma_result_from_GetLastError(GetLastError());
}
*pFile=hFile;
Mr Ms;
}
static Me ma_default_vfs_close__win32(ma_vfs*pVFS,ma_vfs_file file)
{
(Mv)pVFS;
if (CloseHandle((HANDLE)file)==0) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Me ma_default_vfs_read__win32(ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead)
{
Me Mf=Ms;
size_t totalBytesRead;
(Mv)pVFS;
totalBytesRead=0;
while (totalBytesRead<sizeInBytes) {
size_t bytesRemaining;
DWORD bytesToRead;
DWORD bytesRead;
BOOL readResult;
bytesRemaining=sizeInBytes-totalBytesRead;
if (bytesRemaining>=0xFFFFFFFF) {
bytesToRead=0xFFFFFFFF;
} else {
bytesToRead=(DWORD)bytesRemaining;
}
readResult=ReadFile((HANDLE)file,ma_offset_ptr(pDst,totalBytesRead),bytesToRead,&bytesRead,NULL);
if (readResult==1&&bytesRead==0) {
Mf=MA_AT_END;
break;
}
totalBytesRead+=bytesRead;
if (bytesRead<bytesToRead) {
break;
}
if (readResult==0) {
Mf=ma_result_from_GetLastError(GetLastError());
break;
}
}
if (pBytesRead !=NULL) {
*pBytesRead=totalBytesRead;
}
Mr Mf;
}
static Me ma_default_vfs_write__win32(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten)
{
Me Mf=Ms;
size_t totalBytesWritten;
(Mv)pVFS;
totalBytesWritten=0;
while (totalBytesWritten<sizeInBytes) {
size_t bytesRemaining;
DWORD bytesToWrite;
DWORD bytesWritten;
BOOL writeResult;
bytesRemaining=sizeInBytes-totalBytesWritten;
if (bytesRemaining>=0xFFFFFFFF) {
bytesToWrite=0xFFFFFFFF;
} else {
bytesToWrite=(DWORD)bytesRemaining;
}
writeResult=WriteFile((HANDLE)file,ma_offset_ptr(pSrc,totalBytesWritten),bytesToWrite,&bytesWritten,NULL);
totalBytesWritten+=bytesWritten;
if (writeResult==0) {
Mf=ma_result_from_GetLastError(GetLastError());
break;
}
}
if (pBytesWritten !=NULL) {
*pBytesWritten=totalBytesWritten;
}
Mr Mf;
}
static Me ma_default_vfs_seek__win32(ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin)
{
LARGE_INTEGER liDistanceToMove;
DWORD dwMoveMethod;
BOOL Mf;
(Mv)pVFS;
liDistanceToMove.QuadPart=offset; if (origin==ma_seek_origin_current) {
dwMoveMethod=FILE_CURRENT;
} else if (origin==ma_seek_origin_end) {
dwMoveMethod=FILE_END;
} else {
dwMoveMethod=FILE_BEGIN;
}
if (ma_SetFilePointerEx !=NULL) {
Mf=ma_SetFilePointerEx((HANDLE)file,liDistanceToMove,NULL,dwMoveMethod);
} else if (ma_SetFilePointer !=NULL) {
if (offset>0x7FFFFFFF) {
Mr MA_OUT_OF_RANGE;
}
Mf=ma_SetFilePointer((HANDLE)file,(LONG)liDistanceToMove.QuadPart,NULL,dwMoveMethod);
} else {
Mr MA_NOT_IMPLEMENTED;
}
if (Mf==0) {
Mr ma_result_from_GetLastError(GetLastError());
}
Mr Ms;
}
static Me ma_default_vfs_tell__win32(ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor)
{
LARGE_INTEGER liZero;
LARGE_INTEGER liTell;
BOOL Mf;
(Mv)pVFS;
liZero.QuadPart=0;
if (ma_SetFilePointerEx !=NULL) {
Mf=ma_SetFilePointerEx((HANDLE)file,liZero,&liTell,FILE_CURRENT);
} else if (ma_SetFilePointer !=NULL) {
LONG tell;
Mf=ma_SetFilePointer((HANDLE)file,(LONG)liZero.QuadPart,&tell,FILE_CURRENT);
liTell.QuadPart=tell;
} else {
Mr MA_NOT_IMPLEMENTED;
}
if (Mf==0) {
Mr ma_result_from_GetLastError(GetLastError());
}
if (pCursor !=NULL) {
*pCursor=liTell.QuadPart;
}
Mr Ms;
}
static Me ma_default_vfs_info__win32(ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo)
{
BY_HANDLE_FILE_INFORMATION fi;
BOOL Mf;
(Mv)pVFS;
Mf=GetFileInformationByHandle((HANDLE)file,&fi);
if (Mf==0) {
Mr ma_result_from_GetLastError(GetLastError());
}
pInfo->sizeInBytes=((M6)fi.nFileSizeHigh<<32)|((M6)fi.nFileSizeLow);
Mr Ms;
}
#else
static Me ma_default_vfs_open__stdio(ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
Me Mf;
FILE*pFileStd;
const char*pOpenModeStr;
MA_ASSERT(pFilePath !=NULL);
MA_ASSERT(openMode !=0);
MA_ASSERT(pFile !=NULL);
(Mv)pVFS;
if ((openMode&MA_OPEN_MODE_READ) !=0) {
if ((openMode&MA_OPEN_MODE_WRITE) !=0) {
pOpenModeStr = "r+";
} else {
pOpenModeStr = "rb";
}
} else {
pOpenModeStr = "wb";
}
Mf=ma_fopen(&pFileStd,pFilePath,pOpenModeStr);
if (Mf !=Ms) {
Mr Mf;
}
*pFile=pFileStd;
Mr Ms;
}
static Me ma_default_vfs_open_w__stdio(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
Me Mf;
FILE*pFileStd;
const wchar_t*pOpenModeStr;
MA_ASSERT(pFilePath !=NULL);
MA_ASSERT(openMode !=0);
MA_ASSERT(pFile !=NULL);
(Mv)pVFS;
if ((openMode&MA_OPEN_MODE_READ) !=0) {
if ((openMode&MA_OPEN_MODE_WRITE) !=0) {
pOpenModeStr = L"r+";
} else {
pOpenModeStr = L"rb";
}
} else {
pOpenModeStr = L"wb";
}
Mf=ma_wfopen(&pFileStd,pFilePath,pOpenModeStr,(pVFS !=NULL)?&((ma_default_vfs*)pVFS)->allocationCallbacks:NULL);
if (Mf !=Ms) {
Mr Mf;
}
*pFile=pFileStd;
Mr Ms;
}
static Me ma_default_vfs_close__stdio(ma_vfs*pVFS,ma_vfs_file file)
{
MA_ASSERT(file !=NULL);
(Mv)pVFS;
fclose((FILE*)file);
Mr Ms;
}
static Me ma_default_vfs_read__stdio(ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead)
{
size_t Mf;
MA_ASSERT(file !=NULL);
MA_ASSERT(pDst !=NULL);
(Mv)pVFS;
Mf=fread(pDst,1,sizeInBytes,(FILE*)file);
if (pBytesRead !=NULL) {
*pBytesRead=Mf;
}
if (Mf !=sizeInBytes) {
if (Mf==0&&feof((FILE*)file)) {
Mr MA_AT_END;
} else {
Mr ma_result_from_errno(ferror((FILE*)file));
}
}
Mr Ms;
}
static Me ma_default_vfs_write__stdio(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten)
{
size_t Mf;
MA_ASSERT(file !=NULL);
MA_ASSERT(pSrc !=NULL);
(Mv)pVFS;
Mf=fwrite(pSrc,1,sizeInBytes,(FILE*)file);
if (pBytesWritten !=NULL) {
*pBytesWritten=Mf;
}
if (Mf !=sizeInBytes) {
Mr ma_result_from_errno(ferror((FILE*)file));
}
Mr Ms;
}
static Me ma_default_vfs_seek__stdio(ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin)
{
int Mf;
int whence;
MA_ASSERT(file !=NULL);
(Mv)pVFS;
if (origin==ma_seek_origin_start) {
whence=SEEK_SET;
} else if (origin==ma_seek_origin_end) {
whence=SEEK_END;
} else {
whence=SEEK_CUR;
}
#if defined(_WIN32)
#if defined(_MSC_VER)&&_MSC_VER>1200
Mf=_fseeki64((FILE*)file,offset,whence);
#else
if (offset>0x7FFFFFFF) {
Mr MA_OUT_OF_RANGE;
}
Mf=fseek((FILE*)file,(int)offset,whence);
#endif
#else
Mf=fseek((FILE*)file,(long int)offset,whence);
#endif
if (Mf !=0) {
Mr MA_ERROR;
}
Mr Ms;
}
static Me ma_default_vfs_tell__stdio(ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor)
{
ma_int64 Mf;
MA_ASSERT(file !=NULL);
MA_ASSERT(pCursor !=NULL);
(Mv)pVFS;
#if defined(_WIN32)
#if defined(_MSC_VER)&&_MSC_VER>1200
Mf=_ftelli64((FILE*)file);
#else
Mf=ftell((FILE*)file);
#endif
#else
Mf=ftell((FILE*)file);
#endif
*pCursor=Mf;
Mr Ms;
}
#if !defined(_MSC_VER)&&!((defined(_POSIX_C_SOURCE)&&_POSIX_C_SOURCE>=1)||defined(_XOPEN_SOURCE)||defined(_POSIX_SOURCE))&&!defined(MA_BSD)
int fileno(FILE*stream);
#endif
static Me ma_default_vfs_info__stdio(ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo)
{
int fd;
struct stat info;
MA_ASSERT(file !=NULL);
MA_ASSERT(pInfo !=NULL);
(Mv)pVFS;
#if defined(_MSC_VER)
fd=_fileno((FILE*)file);
#else
fd=fileno((FILE*)file);
#endif
if (fstat(fd,&info) !=0) {
Mr ma_result_from_errno(errno);
}
pInfo->sizeInBytes=info.st_size;
Mr Ms;
}
#endif
static Me ma_default_vfs_open(ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
if (pFile==NULL) {
Mr MA_INVALID_ARGS;
}
*pFile=NULL;
if (pFilePath==NULL||openMode==0) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_open__win32(pVFS,pFilePath,openMode,pFile);
#else
Mr ma_default_vfs_open__stdio(pVFS,pFilePath,openMode,pFile);
#endif
}
static Me ma_default_vfs_open_w(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
if (pFile==NULL) {
Mr MA_INVALID_ARGS;
}
*pFile=NULL;
if (pFilePath==NULL||openMode==0) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_open_w__win32(pVFS,pFilePath,openMode,pFile);
#else
Mr ma_default_vfs_open_w__stdio(pVFS,pFilePath,openMode,pFile);
#endif
}
static Me ma_default_vfs_close(ma_vfs*pVFS,ma_vfs_file file)
{
if (file==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_close__win32(pVFS,file);
#else
Mr ma_default_vfs_close__stdio(pVFS,file);
#endif
}
static Me ma_default_vfs_read(ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead)
{
if (pBytesRead !=NULL) {
*pBytesRead=0;
}
if (file==NULL||pDst==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_read__win32(pVFS,file,pDst,sizeInBytes,pBytesRead);
#else
Mr ma_default_vfs_read__stdio(pVFS,file,pDst,sizeInBytes,pBytesRead);
#endif
}
static Me ma_default_vfs_write(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten)
{
if (pBytesWritten !=NULL) {
*pBytesWritten=0;
}
if (file==NULL||pSrc==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_write__win32(pVFS,file,pSrc,sizeInBytes,pBytesWritten);
#else
Mr ma_default_vfs_write__stdio(pVFS,file,pSrc,sizeInBytes,pBytesWritten);
#endif
}
static Me ma_default_vfs_seek(ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin)
{
if (file==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_seek__win32(pVFS,file,offset,origin);
#else
Mr ma_default_vfs_seek__stdio(pVFS,file,offset,origin);
#endif
}
static Me ma_default_vfs_tell(ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor)
{
if (pCursor==NULL) {
Mr MA_INVALID_ARGS;
}
*pCursor=0;
if (file==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_tell__win32(pVFS,file,pCursor);
#else
Mr ma_default_vfs_tell__stdio(pVFS,file,pCursor);
#endif
}
static Me ma_default_vfs_info(ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo)
{
if (pInfo==NULL) {
Mr MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pInfo);
if (file==NULL) {
Mr MA_INVALID_ARGS;
}
#if defined(MA_USE_WIN32_FILEIO)
Mr ma_default_vfs_info__win32(pVFS,file,pInfo);
#else
Mr ma_default_vfs_info__stdio(pVFS,file,pInfo);
#endif
}
MA_API Me ma_default_vfs_init(ma_default_vfs*pVFS,const ma_allocation_callbacks*pAllocationCallbacks)
{
if (pVFS==NULL) {
Mr MA_INVALID_ARGS;
}
pVFS->cb.onOpen=ma_default_vfs_open;
pVFS->cb.onOpenW=ma_default_vfs_open_w;
pVFS->cb.onClose=ma_default_vfs_close;
pVFS->cb.onRead=ma_default_vfs_read;
pVFS->cb.onWrite=ma_default_vfs_write;
pVFS->cb.onSeek=ma_default_vfs_seek;
pVFS->cb.onTell=ma_default_vfs_tell;
pVFS->cb.onInfo=ma_default_vfs_info;
ma_allocation_callbacks_init_copy(&pVFS->allocationCallbacks,pAllocationCallbacks);
Mr Ms;
}
MA_API Me ma_vfs_or_default_open(ma_vfs*pVFS,const char*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
if (pVFS !=NULL) {
Mr ma_vfs_open(pVFS,pFilePath,openMode,pFile);
} else {
Mr ma_default_vfs_open(pVFS,pFilePath,openMode,pFile);
}
}
MA_API Me ma_vfs_or_default_open_w(ma_vfs*pVFS,const wchar_t*pFilePath,M3 openMode,ma_vfs_file*pFile)
{
if (pVFS !=NULL) {
Mr ma_vfs_open_w(pVFS,pFilePath,openMode,pFile);
} else {
Mr ma_default_vfs_open_w(pVFS,pFilePath,openMode,pFile);
}
}
MA_API Me ma_vfs_or_default_close(ma_vfs*pVFS,ma_vfs_file file)
{
if (pVFS !=NULL) {
Mr ma_vfs_close(pVFS,file);
} else {
Mr ma_default_vfs_close(pVFS,file);
}
}
MA_API Me ma_vfs_or_default_read(ma_vfs*pVFS,ma_vfs_file file,Mv*pDst,size_t sizeInBytes,size_t*pBytesRead)
{
if (pVFS !=NULL) {
Mr ma_vfs_read(pVFS,file,pDst,sizeInBytes,pBytesRead);
} else {
Mr ma_default_vfs_read(pVFS,file,pDst,sizeInBytes,pBytesRead);
}
}
MA_API Me ma_vfs_or_default_write(ma_vfs*pVFS,ma_vfs_file file,const Mv*pSrc,size_t sizeInBytes,size_t*pBytesWritten)
{
if (pVFS !=NULL) {
Mr ma_vfs_write(pVFS,file,pSrc,sizeInBytes,pBytesWritten);
} else {
Mr ma_default_vfs_write(pVFS,file,pSrc,sizeInBytes,pBytesWritten);
}
}
MA_API Me ma_vfs_or_default_seek(ma_vfs*pVFS,ma_vfs_file file,ma_int64 offset,ma_seek_origin origin)
{
if (pVFS !=NULL) {
Mr ma_vfs_seek(pVFS,file,offset,origin);
} else {
Mr ma_default_vfs_seek(pVFS,file,offset,origin);
}
}
MA_API Me ma_vfs_or_default_tell(ma_vfs*pVFS,ma_vfs_file file,ma_int64*pCursor)
{
if (pVFS !=NULL) {
Mr ma_vfs_tell(pVFS,file,pCursor);
} else {
Mr ma_default_vfs_tell(pVFS,file,pCursor);
}
}
MA_API Me ma_vfs_or_default_info(ma_vfs*pVFS,ma_vfs_file file,ma_file_info*pInfo)
{
if (pVFS !=NULL) {
Mr ma_vfs_info(pVFS,file,pInfo);
} else {
Mr ma_default_vfs_info(pVFS,file,pInfo);
}
}
static Me ma_vfs_open_and_read_file_ex(ma_vfs*pVFS,const char*pFilePath,const wchar_t*pFilePathW,Mv**ppData,size_t*pSize,const ma_allocation_callbacks*pAllocationCallbacks)
{
Me Mf;
ma_vfs_file file;
ma_file_info info;
Mv*pData;
size_t bytesRead;
if (ppData !=NULL) {
*ppData=NULL;
}
if (pSize !=NULL) {
*pSize=0;
}
if (ppData==NULL) {
Mr MA_INVALID_ARGS;
}
if (pFilePath !=NULL) {
Mf=ma_vfs_or_default_open(pVFS,pFilePath,MA_OPEN_MODE_READ,&file);
} else {
Mf=ma_vfs_or_default_open_w(pVFS,pFilePathW,MA_OPEN_MODE_READ,&file);
}
if (Mf !=Ms) {
Mr Mf;
}
Mf=ma_vfs_or_default_info(pVFS,file,&info);
if (Mf !=Ms) {
ma_vfs_or_default_close(pVFS,file);
Mr Mf;
}
if (info.sizeInBytes>MA_SIZE_MAX) {
ma_vfs_or_default_close(pVFS,file);
Mr MA_TOO_BIG;
}
pData=ma_malloc((size_t)info.sizeInBytes,pAllocationCallbacks);
if (pData==NULL) {
ma_vfs_or_default_close(pVFS,file);
Mr Mf;
}
Mf=ma_vfs_or_default_read(pVFS,file,pData,(size_t)info.sizeInBytes,&bytesRead);
ma_vfs_or_default_close(pVFS,file);
if (Mf !=Ms) {
ma_free(pData,pAllocationCallbacks);
Mr Mf;
}
if (pSize !=NULL) {
*pSize=bytesRead;
}
MA_ASSERT(ppData !=NULL);
*ppData=pData;
Mr Ms;
}
MA_API Me ma_vfs_open_and_read_file(ma_vfs*pVFS,const char*pFilePath,Mv**ppData,size_t*pSize,const ma_allocation_callbacks*pAllocationCallbacks)
{
Mr ma_vfs_open_and_read_file_ex(pVFS,pFilePath,NULL,ppData,pSize,pAllocationCallbacks);
}
MA_API Me ma_vfs_open_and_read_file_w(ma_vfs*pVFS,const wchar_t*pFilePath,Mv**ppData,size_t*pSize,const ma_allocation_callbacks*pAllocationCallbacks)
{
Mr ma_vfs_open_and_read_file_ex(pVFS,NULL,pFilePath,ppData,pSize,pAllocationCallbacks);
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif
#undef Mr
#undef Md
#undef Mc
#undef Me
#undef Mf
#undef M6
#undef M3
#undef Ms
#undef Mv
#undef Mo
#undef Mh
#undef Mp
#undef Mt
#endif

/*
This software is available as a choice of the following licenses. Choose
whichever you prefer.

===============================================================================
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
===============================================================================
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>

===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2025 David Reid

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
