view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.10.21 - 2020-10-30
David Reid - mackron@gmail.com
Website: https://miniaud.io
Documentation: https://miniaud.io/docs
GitHub: https://github.com/mackron/miniaudio
*/
/*
1. Introduction
===============
miniaudio is a single file library for audio playback and capture. To use it, do the following in one .c file:
```c
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
```
You can do `#include "miniaudio.h"` in other parts of the program just like any other header.
miniaudio uses the concept of a "device" as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from,
and then move data to/from the device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a callback which you specify when
initializing the device.
When initializing the device you first need to configure it. The device configuration allows you to specify things like the format of the data delivered via
the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from.
Once you have the device configuration set up you can initialize the device. When initializing a device you need to allocate memory for the device object
beforehand. This gives the application complete control over how the memory is allocated. In the example below we initialize a playback device on the stack,
but you could allocate it on the heap if that suits your situation better.
```c
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
// In playback mode copy data to pOutput. In capture mode read data from pInput. In full-duplex mode, both
// pOutput and pInput will be valid and you can move data from pInput into pOutput. Never process more than
// frameCount frames.
}
int main()
{
ma_device_config config = ma_device_config_init(ma_device_type_playback);
config.playback.format = ma_format_f32; // Set to ma_format_unknown to use the device's native format.
config.playback.channels = 2; // Set to 0 to use the device's native channel count.
config.sampleRate = 48000; // Set to 0 to use the device's native sample rate.
config.dataCallback = data_callback; // This function will be called when miniaudio needs more data.
config.pUserData = pMyCustomData; // Can be accessed from the device object (device.pUserData).
ma_device device;
if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) {
return -1; // Failed to initialize the device.
}
ma_device_start(&device); // The device is sleeping by default so you'll need to start it manually.
// Do something here. Probably your program's main loop.
ma_device_uninit(&device); // This will stop the device so no need to do that manually.
return 0;
}
```
In the example above, `data_callback()` is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted
from the speakers by writing audio data to the output buffer (`pOutput` in the example). In capture mode you read data from the input buffer (`pInput`) to
extract sound captured by the microphone. The `frameCount` parameter tells you how many frames can be written to the output buffer and read from the input
buffer. A "frame" is one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 samples: one for the left, one for the right.
The channel count is defined by the device config. The size in bytes of an individual sample is defined by the sample format which is also specified in the
device config. Multi-channel audio data is always interleaved, which means the samples for each frame are stored next to each other in memory. For example, in
a stereo stream the first pair of samples will be the left and right samples for the first frame, the second pair of samples will be the left and right samples
for the second frame, etc.
The configuration of the device is defined by the `ma_device_config` structure. The config object is always initialized with `ma_device_config_init()`. It's
important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn't break when new members
are added to the `ma_device_config` structure. The example above uses a fairly simple and standard device configuration. The call to `ma_device_config_init()`
takes a single parameter, which is whether or not the device is a playback, capture, duplex or loopback device (loopback devices are not supported on all
backends). The `config.playback.format` member sets the sample format which can be one of the following (all formats are native-endian):
+---------------+----------------------------------------+---------------------------+
| Symbol | Description | Range |
+---------------+----------------------------------------+---------------------------+
| ma_format_f32 | 32-bit floating point | [-1, 1] |
| ma_format_s16 | 16-bit signed integer | [-32768, 32767] |
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
struct
{
ma_bool32 useVerboseDeviceEnumeration;
} alsa;
struct
{
const char* pApplicationName;
const char* pServerName;
ma_bool32 tryAutoSpawn; /* Enables autospawning of the PulseAudio daemon if necessary. */
} pulse;
struct
{
ma_ios_session_category sessionCategory;
ma_uint32 sessionCategoryOptions;
ma_bool32 noAudioSessionActivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. */
ma_bool32 noAudioSessionDeactivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. */
} coreaudio;
struct
{
const char* pClientName;
ma_bool32 tryStartServer;
} jack;
} ma_context_config;
/*
The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`.
Parameters
----------
pContext (in)
A pointer to the context performing the enumeration.
deviceType (in)
The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`.
pInfo (in)
A pointer to a `ma_device_info` containing the ID and name of the enumerated device. Note that this will not include detailed information about the device,
only basic information (ID and name). The reason for this is that it would otherwise require opening the backend device to probe for the information which
is too inefficient.
pUserData (in)
The user data pointer passed into `ma_context_enumerate_devices()`.
*/
typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData);
struct ma_context
{
ma_backend backend; /* DirectSound, ALSA, etc. */
ma_log_proc logCallback;
ma_thread_priority threadPriority;
size_t threadStackSize;
void* pUserData;
ma_allocation_callbacks allocationCallbacks;
ma_mutex deviceEnumLock; /* Used to make ma_context_get_devices() thread safe. */
ma_mutex deviceInfoLock; /* Used to make ma_context_get_device_info() thread safe. */
ma_uint32 deviceInfoCapacity; /* Total capacity of pDeviceInfos. */
ma_uint32 playbackDeviceInfoCount;
ma_uint32 captureDeviceInfoCount;
ma_device_info* pDeviceInfos; /* Playback devices first, then capture. */
ma_bool32 isBackendAsynchronous : 1; /* Set when the context is initialized. Set to 1 for asynchronous backends such as Core Audio and JACK. Do not modify. */
ma_result (* onUninit )(ma_context* pContext);
ma_bool32 (* onDeviceIDEqual )(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1);
ma_result (* onEnumDevices )(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); /* Return false from the callback to stop enumeration. */
ma_result (* onGetDeviceInfo )(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo);
ma_result (* onDeviceInit )(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice);
void (* onDeviceUninit )(ma_device* pDevice);
ma_result (* onDeviceStart )(ma_device* pDevice);
ma_result (* onDeviceStop )(ma_device* pDevice);
ma_result (* onDeviceMainLoop)(ma_device* pDevice);
union
{
#ifdef MA_SUPPORT_WASAPI
struct
{
int _unused;
} wasapi;
#endif
#ifdef MA_SUPPORT_DSOUND
struct
{
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;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
In general, you should not do anything complicated from within the callback. In particular, do not try initializing a device from within the callback. Also,
do not try to call `ma_context_get_device_info()` from within the callback.
Consider using `ma_context_get_devices()` for a simpler and safer API, albeit at the expense of an internal heap allocation.
Example 1 - Simple Enumeration
------------------------------
ma_bool32 ma_device_enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
{
printf("Device Name: %s\n", pInfo->name);
return MA_TRUE;
}
ma_result result = ma_context_enumerate_devices(&context, my_device_enum_callback, pMyUserData);
if (result != MA_SUCCESS) {
// Error.
}
See Also
--------
ma_context_get_devices()
*/
MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
/*
Retrieves basic information about every active playback and/or capture device.
This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos`
parameters. If you do not want to incur the overhead of these allocations consider using `ma_context_enumerate_devices()` which will instead use a callback.
Parameters
----------
pContext (in)
A pointer to the context performing the enumeration.
ppPlaybackDeviceInfos (out)
A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices.
pPlaybackDeviceCount (out)
A pointer to an unsigned integer that will receive the number of playback devices.
ppCaptureDeviceInfos (out)
A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices.
pCaptureDeviceCount (out)
A pointer to an unsigned integer that will receive the number of capture devices.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple
threads. Instead, you need to make a copy of the returned data with your own higher level synchronization.
Remarks
-------
It is _not_ safe to assume the first device in the list is the default device.
You can pass in NULL for the playback or capture lists in which case they'll be ignored.
The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers.
See Also
--------
ma_context_get_devices()
*/
MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount);
/*
Retrieves information about a device of the given type, with the specified ID and share mode.
Parameters
----------
pContext (in)
A pointer to the context performing the query.
deviceType (in)
The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`.
pDeviceID (in)
The ID of the device being queried.
shareMode (in)
The share mode to query for device capabilities. This should be set to whatever you're intending on using when initializing the device. If you're unsure,
set this to `ma_share_mode_shared`.
pDeviceInfo (out)
A pointer to the `ma_device_info` structure that will receive the device information.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. This is guarded using a simple mutex lock.
Remarks
-------
Do _not_ call this from within the `ma_context_enumerate_devices()` callback.
It's possible for a device to have different information and capabilities depending on whether or not it's opened in shared or exclusive mode. For example, in
shared mode, WASAPI always uses floating point samples for mixing, but in exclusive mode it can be anything. Therefore, this function allows you to specify
which share mode you want information for. Note that not all backends and devices support shared or exclusive mode, in which case this function will fail if
the requested share mode is unsupported.
This leaves pDeviceInfo unmodified in the result of an error.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define MA_OPEN_MODE_WRITE 0x00000002
typedef enum
{
ma_seek_origin_start,
ma_seek_origin_current,
ma_seek_origin_end /* Not used by decoders. */
} ma_seek_origin;
typedef struct
{
ma_uint64 sizeInBytes;
} ma_file_info;
typedef struct
{
ma_result (* onOpen) (ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
ma_result (* onOpenW)(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
ma_result (* onClose)(ma_vfs* pVFS, ma_vfs_file file);
ma_result (* onRead) (ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead);
ma_result (* onWrite)(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten);
ma_result (* onSeek) (ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin);
ma_result (* onTell) (ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor);
ma_result (* onInfo) (ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo);
} ma_vfs_callbacks;
MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file);
MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead);
MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten);
MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin);
MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor);
MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo);
MA_API ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks);
typedef struct
{
ma_vfs_callbacks cb;
ma_allocation_callbacks allocationCallbacks; /* Only used for the wchar_t version of open() on non-Windows platforms. */
} ma_default_vfs;
MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks);
#if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)
typedef enum
{
ma_resource_format_wav
} ma_resource_format;
#endif
/************************************************************************************************************************************************************
Decoding
========
Decoders are independent of the main device API. Decoding APIs can be called freely inside the device's data callback, but they are not thread safe unless
you do your own synchronization.
************************************************************************************************************************************************************/
#ifndef MA_NO_DECODING
typedef struct ma_decoder ma_decoder;
typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */
typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin); /* Origin will never be ma_seek_origin_end. */
typedef ma_uint64 (* ma_decoder_read_pcm_frames_proc) (ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); /* Returns the number of frames read. Output data is in internal format. */
typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc) (ma_decoder* pDecoder, ma_uint64 frameIndex);
typedef ma_result (* ma_decoder_uninit_proc) (ma_decoder* pDecoder);
typedef ma_uint64 (* ma_decoder_get_length_in_pcm_frames_proc)(ma_decoder* pDecoder);
typedef struct
{
ma_format format; /* Set to 0 or ma_format_unknown to use the stream's internal format. */
ma_uint32 channels; /* Set to 0 to use the stream's internal channels. */
ma_uint32 sampleRate; /* Set to 0 to use the stream's internal sample rate. */
ma_channel channelMap[MA_MAX_CHANNELS];
ma_channel_mix_mode channelMixMode;
ma_dither_mode ditherMode;
struct
{
ma_resample_algorithm algorithm;
struct
{
ma_uint32 lpfOrder;
} linear;
struct
{
int quality;
} speex;
} resampling;
ma_allocation_callbacks allocationCallbacks;
} ma_decoder_config;
struct ma_decoder
{
ma_data_source_callbacks ds;
ma_decoder_read_proc onRead;
ma_decoder_seek_proc onSeek;
void* pUserData;
ma_uint64 readPointerInBytes; /* In internal encoded data. */
ma_uint64 readPointerInPCMFrames; /* In output sample rate. Used for keeping track of how many frames are available for decoding. */
ma_format internalFormat;
ma_uint32 internalChannels;
ma_uint32 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_format outputFormat;
ma_uint32 outputChannels;
ma_uint32 outputSampleRate;
ma_channel outputChannelMap[MA_MAX_CHANNELS];
ma_data_converter converter; /* <-- Data conversion is achieved by running frames through this. */
ma_allocation_callbacks allocationCallbacks;
ma_decoder_read_pcm_frames_proc onReadPCMFrames;
ma_decoder_seek_to_pcm_frame_proc onSeekToPCMFrame;
ma_decoder_uninit_proc onUninit;
ma_decoder_get_length_in_pcm_frames_proc onGetLengthInPCMFrames;
void* pInternalDecoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
union
{
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate);
MA_API ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder);
/*
Retrieves the current position of the read cursor in PCM frames.
*/
MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor);
/*
Retrieves the length of the decoder in PCM frames.
Do not call this on streams of an undefined length, such as internet radio.
If the length is unknown or an error occurs, 0 will be returned.
This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
uses internally.
For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
This function is not thread safe without your own synchronization.
*/
MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder);
/*
Reads PCM frames from the given decoder.
This is not thread safe without your own synchronization.
*/
MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount);
/*
Seeks to a PCM frame based on it's absolute index.
This is not thread safe without your own synchronization.
*/
MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex);
/*
Retrieves the number of frames that can be read before reaching the end.
This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in
particular ensuring you do not call it on streams of an undefined length, such as internet radio.
If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be
returned.
*/
MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames);
/*
Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input,
pConfig should be set to what you want. On output it will be set to what you got.
*/
MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
#endif /* MA_NO_DECODING */
/************************************************************************************************************************************************************
Encoding
========
Encoders do not perform any format conversion for you. If your target format does not support the format, and error will be returned.
************************************************************************************************************************************************************/
#ifndef MA_NO_ENCODING
typedef struct ma_encoder ma_encoder;
typedef size_t (* ma_encoder_write_proc) (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite); /* Returns the number of bytes written. */
typedef ma_bool32 (* ma_encoder_seek_proc) (ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin);
typedef ma_result (* ma_encoder_init_proc) (ma_encoder* pEncoder);
typedef void (* ma_encoder_uninit_proc) (ma_encoder* pEncoder);
typedef ma_uint64 (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount);
typedef struct
{
ma_resource_format resourceFormat;
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_allocation_callbacks allocationCallbacks;
} ma_encoder_config;
MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate);
struct ma_encoder
{
ma_encoder_config config;
ma_encoder_write_proc onWrite;
ma_encoder_seek_proc onSeek;
ma_encoder_init_proc onInit;
ma_encoder_uninit_proc onUninit;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define c89atomic_test_and_set_explicit_8( dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_16(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_32(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_test_and_set_explicit_64(dst, order) __atomic_exchange_n(dst, 1, order)
#define c89atomic_clear_explicit_8( dst, order) __atomic_store_n(dst, 0, order)
#define c89atomic_clear_explicit_16(dst, order) __atomic_store_n(dst, 0, order)
#define c89atomic_clear_explicit_32(dst, order) __atomic_store_n(dst, 0, order)
#define c89atomic_clear_explicit_64(dst, order) __atomic_store_n(dst, 0, order)
#define c89atomic_store_explicit_8( dst, src, order) __atomic_store_n(dst, src, order)
#define c89atomic_store_explicit_16(dst, src, order) __atomic_store_n(dst, src, order)
#define c89atomic_store_explicit_32(dst, src, order) __atomic_store_n(dst, src, order)
#define c89atomic_store_explicit_64(dst, src, order) __atomic_store_n(dst, src, order)
#define c89atomic_load_explicit_8( dst, order) __atomic_load_n(dst, order)
#define c89atomic_load_explicit_16(dst, order) __atomic_load_n(dst, order)
#define c89atomic_load_explicit_32(dst, order) __atomic_load_n(dst, order)
#define c89atomic_load_explicit_64(dst, order) __atomic_load_n(dst, order)
#define c89atomic_exchange_explicit_8( dst, src, order) __atomic_exchange_n(dst, src, order)
#define c89atomic_exchange_explicit_16(dst, src, order) __atomic_exchange_n(dst, src, order)
#define c89atomic_exchange_explicit_32(dst, src, order) __atomic_exchange_n(dst, src, order)
#define c89atomic_exchange_explicit_64(dst, src, order) __atomic_exchange_n(dst, src, order)
#define c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
#define c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
#define c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
#define c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
#define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
#define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
#define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
#define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
#define c89atomic_fetch_add_explicit_8( dst, src, order) __atomic_fetch_add(dst, src, order)
#define c89atomic_fetch_add_explicit_16(dst, src, order) __atomic_fetch_add(dst, src, order)
#define c89atomic_fetch_add_explicit_32(dst, src, order) __atomic_fetch_add(dst, src, order)
#define c89atomic_fetch_add_explicit_64(dst, src, order) __atomic_fetch_add(dst, src, order)
#define c89atomic_fetch_sub_explicit_8( dst, src, order) __atomic_fetch_sub(dst, src, order)
#define c89atomic_fetch_sub_explicit_16(dst, src, order) __atomic_fetch_sub(dst, src, order)
#define c89atomic_fetch_sub_explicit_32(dst, src, order) __atomic_fetch_sub(dst, src, order)
#define c89atomic_fetch_sub_explicit_64(dst, src, order) __atomic_fetch_sub(dst, src, order)
#define c89atomic_fetch_or_explicit_8( dst, src, order) __atomic_fetch_or(dst, src, order)
#define c89atomic_fetch_or_explicit_16(dst, src, order) __atomic_fetch_or(dst, src, order)
#define c89atomic_fetch_or_explicit_32(dst, src, order) __atomic_fetch_or(dst, src, order)
#define c89atomic_fetch_or_explicit_64(dst, src, order) __atomic_fetch_or(dst, src, order)
#define c89atomic_fetch_xor_explicit_8( dst, src, order) __atomic_fetch_xor(dst, src, order)
#define c89atomic_fetch_xor_explicit_16(dst, src, order) __atomic_fetch_xor(dst, src, order)
#define c89atomic_fetch_xor_explicit_32(dst, src, order) __atomic_fetch_xor(dst, src, order)
#define c89atomic_fetch_xor_explicit_64(dst, src, order) __atomic_fetch_xor(dst, src, order)
#define c89atomic_fetch_and_explicit_8( dst, src, order) __atomic_fetch_and(dst, src, order)
#define c89atomic_fetch_and_explicit_16(dst, src, order) __atomic_fetch_and(dst, src, order)
#define c89atomic_fetch_and_explicit_32(dst, src, order) __atomic_fetch_and(dst, src, order)
#define c89atomic_fetch_and_explicit_64(dst, src, order) __atomic_fetch_and(dst, src, order)
#define c89atomic_compare_and_swap_8 (dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#else
#define c89atomic_memory_order_relaxed 1
#define c89atomic_memory_order_consume 2
#define c89atomic_memory_order_acquire 3
#define c89atomic_memory_order_release 4
#define c89atomic_memory_order_acq_rel 5
#define c89atomic_memory_order_seq_cst 6
#define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#define c89atomic_thread_fence(order) __sync_synchronize()
#define c89atomic_signal_fence(order) c89atomic_thread_fence(order)
static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
{
if (order > c89atomic_memory_order_acquire) {
__sync_synchronize();
}
return __sync_lock_test_and_set(dst, src);
}
static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
{
volatile c89atomic_uint16 oldValue;
do {
oldValue = *dst;
} while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
{
volatile c89atomic_uint32 oldValue;
do {
oldValue = *dst;
} while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
{
volatile c89atomic_uint64 oldValue;
do {
oldValue = *dst;
} while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
(void)order;
return oldValue;
}
#define c89atomic_fetch_add_explicit_8( dst, src, order) __sync_fetch_and_add(dst, src)
#define c89atomic_fetch_add_explicit_16(dst, src, order) __sync_fetch_and_add(dst, src)
#define c89atomic_fetch_add_explicit_32(dst, src, order) __sync_fetch_and_add(dst, src)
#define c89atomic_fetch_add_explicit_64(dst, src, order) __sync_fetch_and_add(dst, src)
#define c89atomic_fetch_sub_explicit_8( dst, src, order) __sync_fetch_and_sub(dst, src)
#define c89atomic_fetch_sub_explicit_16(dst, src, order) __sync_fetch_and_sub(dst, src)
#define c89atomic_fetch_sub_explicit_32(dst, src, order) __sync_fetch_and_sub(dst, src)
#define c89atomic_fetch_sub_explicit_64(dst, src, order) __sync_fetch_and_sub(dst, src)
#define c89atomic_fetch_or_explicit_8( dst, src, order) __sync_fetch_and_or(dst, src)
#define c89atomic_fetch_or_explicit_16(dst, src, order) __sync_fetch_and_or(dst, src)
#define c89atomic_fetch_or_explicit_32(dst, src, order) __sync_fetch_and_or(dst, src)
#define c89atomic_fetch_or_explicit_64(dst, src, order) __sync_fetch_and_or(dst, src)
#define c89atomic_fetch_xor_explicit_8( dst, src, order) __sync_fetch_and_xor(dst, src)
#define c89atomic_fetch_xor_explicit_16(dst, src, order) __sync_fetch_and_xor(dst, src)
#define c89atomic_fetch_xor_explicit_32(dst, src, order) __sync_fetch_and_xor(dst, src)
#define c89atomic_fetch_xor_explicit_64(dst, src, order) __sync_fetch_and_xor(dst, src)
#define c89atomic_fetch_and_explicit_8( dst, src, order) __sync_fetch_and_and(dst, src)
#define c89atomic_fetch_and_explicit_16(dst, src, order) __sync_fetch_and_and(dst, src)
#define c89atomic_fetch_and_explicit_32(dst, src, order) __sync_fetch_and_and(dst, src)
#define c89atomic_fetch_and_explicit_64(dst, src, order) __sync_fetch_and_and(dst, src)
#define c89atomic_compare_and_swap_8( dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_16(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_32(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_compare_and_swap_64(dst, expected, desired) __sync_val_compare_and_swap(dst, expected, desired)
#define c89atomic_load_explicit_8( ptr, order) c89atomic_compare_and_swap_8 (ptr, 0, 0)
#define c89atomic_load_explicit_16(ptr, order) c89atomic_compare_and_swap_16(ptr, 0, 0)
#define c89atomic_load_explicit_32(ptr, order) c89atomic_compare_and_swap_32(ptr, 0, 0)
#define c89atomic_load_explicit_64(ptr, order) c89atomic_compare_and_swap_64(ptr, 0, 0)
#define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order)
#define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (result != MA_SUCCESS) {
break;
}
totalFramesReadOut += framesReadThisIterationOut;
pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
break; /* We're done. */
}
}
}
}
/* A helper for sending sample data to the client. */
static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(frameCountInDeviceFormat > 0);
MA_ASSERT(pFramesInDeviceFormat != NULL);
if (pDevice->capture.converter.isPassthrough) {
ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat);
} else {
ma_result result;
ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint64 framesInClientFormatCap = sizeof(pFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint64 totalDeviceFramesProcessed = 0;
ma_uint64 totalClientFramesProcessed = 0;
const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
/* We just keep going until we've exhaused all of our input frames and cannot generate any more output frames. */
for (;;) {
ma_uint64 deviceFramesProcessedThisIteration;
ma_uint64 clientFramesProcessedThisIteration;
deviceFramesProcessedThisIteration = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
clientFramesProcessedThisIteration = framesInClientFormatCap;
result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &deviceFramesProcessedThisIteration, pFramesInClientFormat, &clientFramesProcessedThisIteration);
if (result != MA_SUCCESS) {
break;
}
if (clientFramesProcessedThisIteration > 0) {
ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */
}
pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
totalDeviceFramesProcessed += deviceFramesProcessedThisIteration;
totalClientFramesProcessed += clientFramesProcessedThisIteration;
if (deviceFramesProcessedThisIteration == 0 && clientFramesProcessedThisIteration == 0) {
break; /* We're done. */
}
}
}
}
/* We only want to expose ma_device__handle_duplex_callback_capture() and ma_device__handle_duplex_callback_playback() if we have an asynchronous backend enabled. */
#if defined(MA_HAS_JACK) || \
defined(MA_HAS_COREAUDIO) || \
defined(MA_HAS_AAUDIO) || \
defined(MA_HAS_OPENSL) || \
defined(MA_HAS_WEBAUDIO)
static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_pcm_rb* pRB)
{
ma_result result;
ma_uint32 totalDeviceFramesProcessed = 0;
const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
MA_ASSERT(pDevice != NULL);
MA_ASSERT(frameCountInDeviceFormat > 0);
MA_ASSERT(pFramesInDeviceFormat != NULL);
MA_ASSERT(pRB != NULL);
/* Write to the ring buffer. The ring buffer is in the client format which means we need to convert. */
for (;;) {
ma_uint32 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
ma_uint32 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint64 framesProcessedInDeviceFormat;
ma_uint64 framesProcessedInClientFormat;
void* pFramesInClientFormat;
result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat);
if (result != MA_SUCCESS) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result);
break;
}
if (framesToProcessInClientFormat == 0) {
if (ma_pcm_rb_pointer_distance(pRB) == (ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) {
break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */
}
}
/* Convert. */
framesProcessedInDeviceFormat = framesToProcessInDeviceFormat;
framesProcessedInClientFormat = framesToProcessInClientFormat;
result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &framesProcessedInDeviceFormat, pFramesInClientFormat, &framesProcessedInClientFormat);
if (result != MA_SUCCESS) {
break;
}
result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat, pFramesInClientFormat); /* Safe cast. */
if (result != MA_SUCCESS) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result);
break;
}
pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, framesProcessedInDeviceFormat * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
totalDeviceFramesProcessed += (ma_uint32)framesProcessedInDeviceFormat; /* Safe cast. */
/* We're done when we're unable to process any client nor device frames. */
if (framesProcessedInClientFormat == 0 && framesProcessedInDeviceFormat == 0) {
break; /* Done. */
}
}
return MA_SUCCESS;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
*/
MA_ZERO_MEMORY(silentInputFrames, sizeof(silentInputFrames));
/* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */
totalFramesToReadFromClient = (ma_uint32)ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, frameCount);
totalFramesReadFromClient = 0;
while (totalFramesReadFromClient < totalFramesToReadFromClient && ma_device_is_started(pDevice)) {
ma_uint32 framesRemainingFromClient;
ma_uint32 framesToProcessFromClient;
ma_uint32 inputFrameCount;
void* pInputFrames;
framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient);
framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
if (framesToProcessFromClient > framesRemainingFromClient) {
framesToProcessFromClient = framesRemainingFromClient;
}
/* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */
inputFrameCount = framesToProcessFromClient;
result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames);
if (result == MA_SUCCESS) {
if (inputFrameCount > 0) {
/* Use actual input frames. */
ma_device__on_data(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount);
} else {
if (ma_pcm_rb_pointer_distance(pRB) == 0) {
break; /* Underrun. */
}
}
/* We're done with the captured samples. */
result = ma_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames);
if (result != MA_SUCCESS) {
break; /* Don't know what to do here... Just abandon ship. */
}
} else {
/* Use silent input frames. */
inputFrameCount = ma_min(
sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels),
sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)
);
ma_device__on_data(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount);
}
/* We have samples in external format so now we need to convert to internal format and output to the device. */
{
ma_uint64 framesConvertedIn = inputFrameCount;
ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut);
ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackFramesInExternalFormat, &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut);
totalFramesReadFromClient += (ma_uint32)framesConvertedIn; /* Safe cast. */
totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */
pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
}
}
return MA_SUCCESS;
}
#endif /* Asynchronous backends. */
/* A helper for changing the state of the device. */
static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newState)
{
c89atomic_exchange_32(&pDevice->state, newState);
}
/* A helper for getting the state of the device. */
static MA_INLINE ma_uint32 ma_device__get_state(ma_device* pDevice)
{
return pDevice->state;
}
#ifdef MA_WIN32
GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
/*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
/*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
#endif
typedef struct
{
ma_device_type deviceType;
const ma_device_id* pDeviceID;
char* pName;
size_t nameBufferSize;
ma_bool32 foundDevice;
} ma_context__try_get_device_name_by_id__enum_callback_data;
static ma_bool32 ma_context__try_get_device_name_by_id__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData)
{
ma_context__try_get_device_name_by_id__enum_callback_data* pData = (ma_context__try_get_device_name_by_id__enum_callback_data*)pUserData;
MA_ASSERT(pData != NULL);
if (pData->deviceType == deviceType) {
if (pContext->onDeviceIDEqual(pContext, pData->pDeviceID, &pDeviceInfo->id)) {
ma_strncpy_s(pData->pName, pData->nameBufferSize, pDeviceInfo->name, (size_t)-1);
pData->foundDevice = MA_TRUE;
}
}
return !pData->foundDevice;
}
/*
Generic function for retrieving the name of a device by it's ID.
This function simply enumerates every device and then retrieves the name of the first device that has the same ID.
*/
static ma_result ma_context__try_get_device_name_by_id(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, char* pName, size_t nameBufferSize)
{
ma_result result;
ma_context__try_get_device_name_by_id__enum_callback_data data;
MA_ASSERT(pContext != NULL);
MA_ASSERT(pName != NULL);
if (pDeviceID == NULL) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
case ma_device_type_playback:
{
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
framesToWriteThisIteration = playbackDeviceDataCapInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
result = ma_device_write__null(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device is started. */
ma_device_stop__null(pDevice);
return result;
}
static ma_result ma_context_uninit__null(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_null);
(void)pContext;
return MA_SUCCESS;
}
static ma_result ma_context_init__null(const ma_context_config* pConfig, ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
(void)pConfig;
pContext->onUninit = ma_context_uninit__null;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__null;
pContext->onEnumDevices = ma_context_enumerate_devices__null;
pContext->onGetDeviceInfo = ma_context_get_device_info__null;
pContext->onDeviceInit = ma_device_init__null;
pContext->onDeviceUninit = ma_device_uninit__null;
pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
pContext->onDeviceMainLoop = ma_device_main_loop__null;
/* The null backend always works. */
return MA_SUCCESS;
}
#endif
/*******************************************************************************
WIN32 COMMON
*******************************************************************************/
#if defined(MA_WIN32)
#if defined(MA_WIN32_DESKTOP)
#define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit)
#define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)()
#define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv)
#define ma_CoTaskMemFree(pContext, pv) ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv)
#define ma_PropVariantClear(pContext, pvar) ((MA_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar)
#else
#define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) CoInitializeEx(pvReserved, dwCoInit)
#define ma_CoUninitialize(pContext) CoUninitialize()
#define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv)
#define ma_CoTaskMemFree(pContext, pv) CoTaskMemFree(pv)
#define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar)
#endif
#if !defined(MAXULONG_PTR)
typedef size_t DWORD_PTR;
#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
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
{
#ifdef MA_DEBUG_OUTPUT
/*printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
#endif
/* We don't need to worry about this event for our purposes. */
(void)pThis;
(void)pDeviceID;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
{
#ifdef MA_DEBUG_OUTPUT
/*printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
#endif
/* We don't need to worry about this event for our purposes. */
(void)pThis;
(void)pDeviceID;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID)
{
#ifdef MA_DEBUG_OUTPUT
/*printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)");*/
#endif
/* We only ever use the eConsole role in miniaudio. */
if (role != ma_eConsole) {
return S_OK;
}
/* We only care about devices with the same data flow and role as the current device. */
if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) ||
(pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture)) {
return S_OK;
}
/* Don't do automatic stream routing if we're not allowed. */
if ((dataFlow == ma_eRender && pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting == MA_FALSE) ||
(dataFlow == ma_eCapture && pThis->pDevice->wasapi.allowCaptureAutoStreamRouting == MA_FALSE)) {
return S_OK;
}
/*
Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to
AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once
it's fixed.
*/
if ((dataFlow == ma_eRender && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) ||
(dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode == ma_share_mode_exclusive)) {
return S_OK;
}
/*
We don't change the device here - we change it in the worker thread to keep synchronization simple. To do this I'm just setting a flag to
indicate that the default device has changed. Loopback devices are treated as capture devices so we need to do a bit of a dance to handle
that properly.
*/
if (dataFlow == ma_eRender && pThis->pDevice->type != ma_device_type_loopback) {
c89atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultPlaybackDeviceChanged, MA_TRUE);
}
if (dataFlow == ma_eCapture || pThis->pDevice->type == ma_device_type_loopback) {
c89atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_TRUE);
}
(void)pDefaultDeviceID;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key)
{
#ifdef MA_DEBUG_OUTPUT
/*printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
#endif
(void)pThis;
(void)pDeviceID;
(void)key;
return 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 /* MA_WIN32_DESKTOP */
#ifdef MA_WIN32_DESKTOP
typedef ma_IMMDevice ma_WASAPIDeviceInterface;
#else
typedef ma_IUnknown ma_WASAPIDeviceInterface;
#endif
static ma_bool32 ma_context_is_device_id_equal__wasapi(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pID0 != NULL);
MA_ASSERT(pID1 != NULL);
(void)pContext;
return memcmp(pID0->wasapi, pID1->wasapi, sizeof(pID0->wasapi)) == 0;
}
static void ma_set_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_device_info* pInfo)
{
MA_ASSERT(pWF != NULL);
MA_ASSERT(pInfo != NULL);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device is started. */
ma_device_stop__winmm(pDevice);
return result;
}
static ma_result ma_context_uninit__winmm(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_winmm);
ma_dlclose(pContext, pContext->winmm.hWinMM);
return MA_SUCCESS;
}
static ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
(void)pConfig;
pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll");
if (pContext->winmm.hWinMM == NULL) {
return MA_NO_BACKEND;
}
pContext->winmm.waveOutGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs");
pContext->winmm.waveOutGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA");
pContext->winmm.waveOutOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen");
pContext->winmm.waveOutClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose");
pContext->winmm.waveOutPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader");
pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader");
pContext->winmm.waveOutWrite = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite");
pContext->winmm.waveOutReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset");
pContext->winmm.waveInGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs");
pContext->winmm.waveInGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA");
pContext->winmm.waveInOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen");
pContext->winmm.waveInClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose");
pContext->winmm.waveInPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader");
pContext->winmm.waveInUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader");
pContext->winmm.waveInAddBuffer = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer");
pContext->winmm.waveInStart = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart");
pContext->winmm.waveInReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset");
pContext->onUninit = ma_context_uninit__winmm;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__winmm;
pContext->onEnumDevices = ma_context_enumerate_devices__winmm;
pContext->onGetDeviceInfo = ma_context_get_device_info__winmm;
pContext->onDeviceInit = ma_device_init__winmm;
pContext->onDeviceUninit = ma_device_uninit__winmm;
pContext->onDeviceStart = NULL; /* Not used with synchronous backends. */
pContext->onDeviceStop = NULL; /* Not used with synchronous backends. */
pContext->onDeviceMainLoop = ma_device_main_loop__winmm;
return MA_SUCCESS;
}
#endif
/******************************************************************************
ALSA Backend
******************************************************************************/
#ifdef MA_HAS_ALSA
#ifdef MA_NO_RUNTIME_LINKING
/* asoundlib.h marks some functions with "inline" which isn't always supported. Need to emulate it. */
#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;
/* snd_pcm_stream_t */
#define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK
#define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE
/* snd_pcm_format_t */
#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
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (pContext->jack.jackSO == NULL) {
return MA_NO_BACKEND;
}
pContext->jack.jack_client_open = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open");
pContext->jack.jack_client_close = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close");
pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size");
pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback");
pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback");
pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown");
pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate");
pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size");
pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports");
pContext->jack.jack_activate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate");
pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate");
pContext->jack.jack_connect = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect");
pContext->jack.jack_port_register = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register");
pContext->jack.jack_port_name = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name");
pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer");
pContext->jack.jack_free = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free");
#else
/*
This strange assignment system is here just to ensure type safety of miniaudio's function pointer
types. If anything differs slightly the compiler should throw a warning.
*/
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;
pContext->jack.jack_client_open = (ma_proc)_jack_client_open;
pContext->jack.jack_client_close = (ma_proc)_jack_client_close;
pContext->jack.jack_client_name_size = (ma_proc)_jack_client_name_size;
pContext->jack.jack_set_process_callback = (ma_proc)_jack_set_process_callback;
pContext->jack.jack_set_buffer_size_callback = (ma_proc)_jack_set_buffer_size_callback;
pContext->jack.jack_on_shutdown = (ma_proc)_jack_on_shutdown;
pContext->jack.jack_get_sample_rate = (ma_proc)_jack_get_sample_rate;
pContext->jack.jack_get_buffer_size = (ma_proc)_jack_get_buffer_size;
pContext->jack.jack_get_ports = (ma_proc)_jack_get_ports;
pContext->jack.jack_activate = (ma_proc)_jack_activate;
pContext->jack.jack_deactivate = (ma_proc)_jack_deactivate;
pContext->jack.jack_connect = (ma_proc)_jack_connect;
pContext->jack.jack_port_register = (ma_proc)_jack_port_register;
pContext->jack.jack_port_name = (ma_proc)_jack_port_name;
pContext->jack.jack_port_get_buffer = (ma_proc)_jack_port_get_buffer;
pContext->jack.jack_free = (ma_proc)_jack_free;
#endif
pContext->isBackendAsynchronous = MA_TRUE;
pContext->onUninit = ma_context_uninit__jack;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__jack;
pContext->onEnumDevices = ma_context_enumerate_devices__jack;
pContext->onGetDeviceInfo = ma_context_get_device_info__jack;
pContext->onDeviceInit = ma_device_init__jack;
pContext->onDeviceUninit = ma_device_uninit__jack;
pContext->onDeviceStart = ma_device_start__jack;
pContext->onDeviceStop = ma_device_stop__jack;
if (pConfig->jack.pClientName != NULL) {
pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName, &pContext->allocationCallbacks);
}
pContext->jack.tryStartServer = pConfig->jack.tryStartServer;
/*
Getting here means the JACK library is installed, but it doesn't necessarily mean it's usable. We need to quickly test this by connecting
a temporary client.
*/
{
ma_jack_client_t* pDummyClient;
ma_result result = ma_context_open_client__jack(pContext, &pDummyClient);
if (result != MA_SUCCESS) {
ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(pContext, pContext->jack.jackSO);
#endif
return MA_NO_BACKEND;
}
((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDummyClient);
}
return MA_SUCCESS;
}
#endif /* JACK */
/******************************************************************************
Core Audio Backend
******************************************************************************/
#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
#else
#define MA_APPLE_DESKTOP
#endif
#if defined(MA_APPLE_DESKTOP)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*
It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to
AudioToolbox.
*/
pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
if (pContext->coreaudio.hAudioUnit == NULL) {
ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
return MA_API_NOT_FOUND;
}
if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) {
/* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */
ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox");
if (pContext->coreaudio.hAudioUnit == NULL) {
ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
return MA_API_NOT_FOUND;
}
}
pContext->coreaudio.AudioComponentFindNext = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext");
pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose");
pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew");
pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart");
pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop");
pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener");
pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo");
pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty");
pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty");
pContext->coreaudio.AudioUnitInitialize = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize");
pContext->coreaudio.AudioUnitRender = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender");
#else
pContext->coreaudio.CFStringGetCString = (ma_proc)CFStringGetCString;
pContext->coreaudio.CFRelease = (ma_proc)CFRelease;
#if defined(MA_APPLE_DESKTOP)
pContext->coreaudio.AudioObjectGetPropertyData = (ma_proc)AudioObjectGetPropertyData;
pContext->coreaudio.AudioObjectGetPropertyDataSize = (ma_proc)AudioObjectGetPropertyDataSize;
pContext->coreaudio.AudioObjectSetPropertyData = (ma_proc)AudioObjectSetPropertyData;
pContext->coreaudio.AudioObjectAddPropertyListener = (ma_proc)AudioObjectAddPropertyListener;
pContext->coreaudio.AudioObjectRemovePropertyListener = (ma_proc)AudioObjectRemovePropertyListener;
#endif
pContext->coreaudio.AudioComponentFindNext = (ma_proc)AudioComponentFindNext;
pContext->coreaudio.AudioComponentInstanceDispose = (ma_proc)AudioComponentInstanceDispose;
pContext->coreaudio.AudioComponentInstanceNew = (ma_proc)AudioComponentInstanceNew;
pContext->coreaudio.AudioOutputUnitStart = (ma_proc)AudioOutputUnitStart;
pContext->coreaudio.AudioOutputUnitStop = (ma_proc)AudioOutputUnitStop;
pContext->coreaudio.AudioUnitAddPropertyListener = (ma_proc)AudioUnitAddPropertyListener;
pContext->coreaudio.AudioUnitGetPropertyInfo = (ma_proc)AudioUnitGetPropertyInfo;
pContext->coreaudio.AudioUnitGetProperty = (ma_proc)AudioUnitGetProperty;
pContext->coreaudio.AudioUnitSetProperty = (ma_proc)AudioUnitSetProperty;
pContext->coreaudio.AudioUnitInitialize = (ma_proc)AudioUnitInitialize;
pContext->coreaudio.AudioUnitRender = (ma_proc)AudioUnitRender;
#endif
pContext->isBackendAsynchronous = MA_TRUE;
pContext->onUninit = ma_context_uninit__coreaudio;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__coreaudio;
pContext->onEnumDevices = ma_context_enumerate_devices__coreaudio;
pContext->onGetDeviceInfo = ma_context_get_device_info__coreaudio;
pContext->onDeviceInit = ma_device_init__coreaudio;
pContext->onDeviceUninit = ma_device_uninit__coreaudio;
pContext->onDeviceStart = ma_device_start__coreaudio;
pContext->onDeviceStop = ma_device_stop__coreaudio;
/* Audio component. */
{
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;
pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
if (pContext->coreaudio.component == NULL) {
#if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
#endif
return MA_FAILED_TO_INIT_BACKEND;
}
}
#if !defined(MA_APPLE_MOBILE)
result = ma_context__init_device_tracking__coreaudio(pContext);
if (result != MA_SUCCESS) {
#if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
#endif
return result;
}
#endif
pContext->coreaudio.noAudioSessionDeactivate = pConfig->coreaudio.noAudioSessionDeactivate;
return MA_SUCCESS;
}
#endif /* Core Audio */
/******************************************************************************
sndio Backend
******************************************************************************/
#ifdef MA_HAS_SNDIO
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return result;
}
static ma_result ma_context_uninit__sndio(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_sndio);
(void)pContext;
return MA_SUCCESS;
}
static ma_result ma_context_init__sndio(const ma_context_config* pConfig, ma_context* pContext)
{
#ifndef MA_NO_RUNTIME_LINKING
const char* libsndioNames[] = {
"libsndio.so"
};
size_t i;
for (i = 0; i < ma_countof(libsndioNames); ++i) {
pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]);
if (pContext->sndio.sndioSO != NULL) {
break;
}
}
if (pContext->sndio.sndioSO == NULL) {
return MA_NO_BACKEND;
}
pContext->sndio.sio_open = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open");
pContext->sndio.sio_close = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close");
pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar");
pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar");
pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap");
pContext->sndio.sio_write = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write");
pContext->sndio.sio_read = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read");
pContext->sndio.sio_start = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start");
pContext->sndio.sio_stop = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop");
pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar");
#else
pContext->sndio.sio_open = sio_open;
pContext->sndio.sio_close = sio_close;
pContext->sndio.sio_setpar = sio_setpar;
pContext->sndio.sio_getpar = sio_getpar;
pContext->sndio.sio_getcap = sio_getcap;
pContext->sndio.sio_write = sio_write;
pContext->sndio.sio_read = sio_read;
pContext->sndio.sio_start = sio_start;
pContext->sndio.sio_stop = sio_stop;
pContext->sndio.sio_initpar = sio_initpar;
#endif
pContext->onUninit = ma_context_uninit__sndio;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__sndio;
pContext->onEnumDevices = ma_context_enumerate_devices__sndio;
pContext->onGetDeviceInfo = ma_context_get_device_info__sndio;
pContext->onDeviceInit = ma_device_init__sndio;
pContext->onDeviceUninit = ma_device_uninit__sndio;
pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
pContext->onDeviceMainLoop = ma_device_main_loop__sndio;
(void)pConfig;
return MA_SUCCESS;
}
#endif /* sndio */
/******************************************************************************
audio(4) Backend
******************************************************************************/
#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>
#if defined(__OpenBSD__)
#include <sys/param.h>
#if defined(OpenBSD) && OpenBSD >= 201709
#define MA_AUDIO4_USE_NEW_API
#endif
#endif
static void 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 ma_result 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) {
return MA_ERROR; /* Doesn't look like the id starts with the base. */
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[8192];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
framesToWriteThisIteration = intermediaryBufferSizeInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
result = ma_device_write__audio4(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device is stopped. */
ma_device_stop__audio4(pDevice);
return result;
}
static ma_result ma_context_uninit__audio4(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_audio4);
(void)pContext;
return MA_SUCCESS;
}
static ma_result ma_context_init__audio4(const ma_context_config* pConfig, ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
(void)pConfig;
pContext->onUninit = ma_context_uninit__audio4;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__audio4;
pContext->onEnumDevices = ma_context_enumerate_devices__audio4;
pContext->onGetDeviceInfo = ma_context_get_device_info__audio4;
pContext->onDeviceInit = ma_device_init__audio4;
pContext->onDeviceUninit = ma_device_uninit__audio4;
pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
pContext->onDeviceMainLoop = ma_device_main_loop__audio4;
return MA_SUCCESS;
}
#endif /* audio4 */
/******************************************************************************
OSS Backend
******************************************************************************/
#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
static int ma_open_temp_device__oss()
{
/* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */
int fd = open("/dev/mixer", O_RDONLY, 0);
if (fd >= 0) {
return fd;
}
return -1;
}
static ma_result ma_context_open_device__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, int* pfd)
{
const char* deviceName;
int flags;
MA_ASSERT(pContext != NULL);
MA_ASSERT(pfd != NULL);
(void)pContext;
*pfd = -1;
/* This function should only be called for playback or capture, not duplex. */
if (deviceType == ma_device_type_duplex) {
return MA_INVALID_ARGS;
}
deviceName = "/dev/dsp";
if (pDeviceID != NULL) {
deviceName = pDeviceID->oss;
}
flags = (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY;
if (shareMode == ma_share_mode_exclusive) {
flags |= O_EXCL;
}
*pfd = open(deviceName, flags, 0);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device is stopped. */
ma_device_stop__oss(pDevice);
return result;
}
static ma_result ma_context_uninit__oss(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_oss);
(void)pContext;
return MA_SUCCESS;
}
static ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_context* pContext)
{
int fd;
int ossVersion;
int result;
MA_ASSERT(pContext != NULL);
(void)pConfig;
/* Try opening a temporary device first so we can get version information. This is closed at the end. */
fd = ma_open_temp_device__oss();
if (fd == -1) {
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.", MA_NO_BACKEND); /* Looks liks OSS isn't installed, or there are no available devices. */
}
/* Grab the OSS version. */
ossVersion = 0;
result = ioctl(fd, OSS_GETVERSION, &ossVersion);
if (result == -1) {
close(fd);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.", MA_NO_BACKEND);
}
pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16);
pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8);
pContext->onUninit = ma_context_uninit__oss;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__oss;
pContext->onEnumDevices = ma_context_enumerate_devices__oss;
pContext->onGetDeviceInfo = ma_context_get_device_info__oss;
pContext->onDeviceInit = ma_device_init__oss;
pContext->onDeviceUninit = ma_device_uninit__oss;
pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
pContext->onDeviceMainLoop = ma_device_main_loop__oss;
close(fd);
return MA_SUCCESS;
}
#endif /* OSS */
/******************************************************************************
AAudio Backend
******************************************************************************/
#ifdef MA_HAS_AAUDIO
/*#include <AAudio/AAudio.h>*/
#define MA_AAUDIO_UNSPECIFIED 0
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_data_callback_result_t;
/* Result codes. miniaudio only cares about the success code. */
#define MA_AAUDIO_OK 0
/* Directions. */
#define MA_AAUDIO_DIRECTION_OUTPUT 0
#define MA_AAUDIO_DIRECTION_INPUT 1
/* Sharing modes. */
#define MA_AAUDIO_SHARING_MODE_EXCLUSIVE 0
#define MA_AAUDIO_SHARING_MODE_SHARED 1
/* Formats. */
#define MA_AAUDIO_FORMAT_PCM_I16 1
#define MA_AAUDIO_FORMAT_PCM_FLOAT 2
/* Stream states. */
#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
/* Performance modes. */
#define MA_AAUDIO_PERFORMANCE_MODE_NONE 10
#define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING 11
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return MA_SUCCESS;
}
static ma_result ma_context_uninit__aaudio(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_aaudio);
ma_dlclose(pContext, pContext->aaudio.hAAudio);
pContext->aaudio.hAAudio = NULL;
return MA_SUCCESS;
}
static ma_result ma_context_init__aaudio(const ma_context_config* pConfig, ma_context* pContext)
{
const char* libNames[] = {
"libaaudio.so"
};
size_t i;
for (i = 0; i < ma_countof(libNames); ++i) {
pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]);
if (pContext->aaudio.hAAudio != NULL) {
break;
}
}
if (pContext->aaudio.hAAudio == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder");
pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete");
pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId");
pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection");
pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode");
pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat");
pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount");
pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate");
pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames");
pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback");
pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback");
pContext->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback");
pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode");
pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream");
pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close");
pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState");
pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange");
pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat");
pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount");
pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate");
pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames");
pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback");
pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst");
pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart");
pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop");
pContext->isBackendAsynchronous = MA_TRUE;
pContext->onUninit = ma_context_uninit__aaudio;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__aaudio;
pContext->onEnumDevices = ma_context_enumerate_devices__aaudio;
pContext->onGetDeviceInfo = ma_context_get_device_info__aaudio;
pContext->onDeviceInit = ma_device_init__aaudio;
pContext->onDeviceUninit = ma_device_uninit__aaudio;
pContext->onDeviceStart = ma_device_start__aaudio;
pContext->onDeviceStop = ma_device_stop__aaudio;
(void)pConfig;
return MA_SUCCESS;
}
#endif /* AAudio */
/******************************************************************************
OpenSL|ES Backend
******************************************************************************/
#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);
/* OpenSL|ES has one-per-application objects :( */
static SLObjectItf g_maEngineObjectSL = NULL;
static SLEngineItf g_maEngineSL = NULL;
static ma_uint32 g_maOpenSLInitCounter = 0;
static ma_spinlock g_maOpenSLSpinlock = 0; /* For init/uninit. */
#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 ma_result ma_result_from_OpenSL(SLuint32 result)
{
switch (result)
{
case SL_RESULT_SUCCESS: return MA_SUCCESS;
case SL_RESULT_PRECONDITIONS_VIOLATED: return MA_ERROR;
case SL_RESULT_PARAMETER_INVALID: return MA_INVALID_ARGS;
case SL_RESULT_MEMORY_FAILURE: return MA_OUT_OF_MEMORY;
case SL_RESULT_RESOURCE_ERROR: return MA_INVALID_DATA;
case SL_RESULT_RESOURCE_LOST: return MA_ERROR;
case SL_RESULT_IO_ERROR: return MA_IO_ERROR;
case SL_RESULT_BUFFER_INSUFFICIENT: return MA_NO_SPACE;
case SL_RESULT_CONTENT_CORRUPTED: return MA_INVALID_DATA;
case SL_RESULT_CONTENT_UNSUPPORTED: return MA_FORMAT_NOT_SUPPORTED;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
for (i = 0; i < ma_countof(libOpenSLESNames); i += 1) {
pContext->opensl.libOpenSLES = ma_dlopen(pContext, libOpenSLESNames[i]);
if (pContext->opensl.libOpenSLES != NULL) {
break;
}
}
if (pContext->opensl.libOpenSLES == NULL) {
return MA_NO_BACKEND; /* Couldn't find libOpenSLES.so */
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ENGINE", &pContext->opensl.SL_IID_ENGINE);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_AUDIOIODEVICECAPABILITIES", &pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_RECORD", &pContext->opensl.SL_IID_RECORD);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_PLAY", &pContext->opensl.SL_IID_PLAY);
if (result != MA_SUCCESS) {
return result;
}
result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_OUTPUTMIX", &pContext->opensl.SL_IID_OUTPUTMIX);
if (result != MA_SUCCESS) {
return result;
}
pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(pContext, pContext->opensl.libOpenSLES, "slCreateEngine");
if (pContext->opensl.slCreateEngine == NULL) {
ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol slCreateEngine.");
return MA_NO_BACKEND;
}
/* Initialize global data first if applicable. */
ma_spinlock_lock(&g_maOpenSLSpinlock);
{
result = ma_context_init_engine_nolock__opensl(pContext);
}
ma_spinlock_unlock(&g_maOpenSLSpinlock);
if (result != MA_SUCCESS) {
return result; /* Failed to initialize the OpenSL engine. */
}
pContext->isBackendAsynchronous = MA_TRUE;
pContext->onUninit = ma_context_uninit__opensl;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__opensl;
pContext->onEnumDevices = ma_context_enumerate_devices__opensl;
pContext->onGetDeviceInfo = ma_context_get_device_info__opensl;
pContext->onDeviceInit = ma_device_init__opensl;
pContext->onDeviceUninit = ma_device_uninit__opensl;
pContext->onDeviceStart = ma_device_start__opensl;
pContext->onDeviceStop = ma_device_stop__opensl;
return MA_SUCCESS;
}
#endif /* OpenSL|ES */
/******************************************************************************
Web Audio Backend
******************************************************************************/
#ifdef MA_HAS_WEBAUDIO
#include <emscripten/emscripten.h>
static ma_bool32 ma_is_capture_supported__webaudio()
{
return EM_ASM_INT({
return (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined);
}, 0) != 0; /* Must pass in a dummy argument for C99 compatibility. */
}
#ifdef __cplusplus
extern "C" {
#endif
void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
{
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_capture(pDevice, (ma_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB);
} else {
ma_device__send_frames_to_client(pDevice, (ma_uint32)frameCount, pFrames); /* Send directly to the client. */
}
}
void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_playback__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
{
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_playback(pDevice, (ma_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB);
} else {
ma_device__read_frames_from_client(pDevice, (ma_uint32)frameCount, pFrames); /* Read directly from the device. */
}
}
#ifdef __cplusplus
}
#endif
static ma_bool32 ma_context_is_device_id_equal__webaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pID0 != NULL);
MA_ASSERT(pID1 != NULL);
(void)pContext;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* Here is where our global JavaScript object is initialized. */
resultFromJS = EM_ASM_INT({
if ((window.AudioContext || window.webkitAudioContext) === undefined) {
return 0; /* Web Audio not supported. */
}
if (typeof(miniaudio) === 'undefined') {
miniaudio = {};
miniaudio.devices = []; /* Device cache for mapping devices to indexes for JavaScript/C interop. */
miniaudio.track_device = function(device) {
/* Try inserting into a free slot first. */
for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
if (miniaudio.devices[iDevice] == null) {
miniaudio.devices[iDevice] = device;
return iDevice;
}
}
/* Getting here means there is no empty slots in the array so we just push to the end. */
miniaudio.devices.push(device);
return miniaudio.devices.length - 1;
};
miniaudio.untrack_device_by_index = function(deviceIndex) {
/* We just set the device's slot to null. The slot will get reused in the next call to ma_track_device. */
miniaudio.devices[deviceIndex] = null;
/* Trim the array if possible. */
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) {
return miniaudio.untrack_device_by_index(iDevice);
}
}
};
miniaudio.get_device_by_index = function(deviceIndex) {
return miniaudio.devices[deviceIndex];
};
}
return 1;
}, 0); /* Must pass in a dummy argument for C99 compatibility. */
if (resultFromJS != 1) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->isBackendAsynchronous = MA_TRUE;
pContext->onUninit = ma_context_uninit__webaudio;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__webaudio;
pContext->onEnumDevices = ma_context_enumerate_devices__webaudio;
pContext->onGetDeviceInfo = ma_context_get_device_info__webaudio;
pContext->onDeviceInit = ma_device_init__webaudio;
pContext->onDeviceUninit = ma_device_uninit__webaudio;
pContext->onDeviceStart = ma_device_start__webaudio;
pContext->onDeviceStop = ma_device_stop__webaudio;
(void)pConfig; /* Unused. */
return MA_SUCCESS;
}
#endif /* Web Audio */
static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint32 channels)
{
/* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */
if (channelMap[0] != MA_CHANNEL_NONE) {
ma_uint32 iChannel;
if (channels == 0 || channels > MA_MAX_CHANNELS) {
return MA_FALSE; /* Channel count out of range. */
}
/* A channel cannot be present in the channel map more than once. */
for (iChannel = 0; iChannel < channels; ++iChannel) {
ma_uint32 jChannel;
for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) {
if (channelMap[iChannel] == channelMap[jChannel]) {
return MA_FALSE;
}
}
}
}
return MA_TRUE;
}
static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType)
{
ma_result result;
MA_ASSERT(pDevice != NULL);
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
if (pDevice->capture.usingDefaultFormat) {
pDevice->capture.format = pDevice->capture.internalFormat;
}
if (pDevice->capture.usingDefaultChannels) {
pDevice->capture.channels = pDevice->capture.internalChannels;
}
if (pDevice->capture.usingDefaultChannelMap) {
MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS);
if (pDevice->capture.internalChannels == pDevice->capture.channels) {
ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels);
} else {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock");
pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock");
pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init");
pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy");
pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait");
pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal");
pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init");
pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy");
pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam");
pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam");
#else
pContext->posix.pthread_create = (ma_proc)pthread_create;
pContext->posix.pthread_join = (ma_proc)pthread_join;
pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init;
pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy;
pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock;
pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock;
pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init;
pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy;
pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait;
pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal;
pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init;
pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy;
#if !defined(__EMSCRIPTEN__)
pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy;
pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam;
pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam;
#endif
#endif
return MA_SUCCESS;
}
#endif
static ma_result ma_context_init_backend_apis(ma_context* pContext)
{
ma_result result;
#ifdef MA_WIN32
result = ma_context_init_backend_apis__win32(pContext);
#else
result = ma_context_init_backend_apis__nix(pContext);
#endif
return result;
}
static ma_result ma_context_uninit_backend_apis(ma_context* pContext)
{
ma_result result;
#ifdef MA_WIN32
result = ma_context_uninit_backend_apis__win32(pContext);
#else
result = ma_context_uninit_backend_apis__nix(pContext);
#endif
return result;
}
static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext)
{
return pContext->isBackendAsynchronous;
}
MA_API ma_context_config ma_context_config_init()
{
ma_context_config config;
MA_ZERO_OBJECT(&config);
return config;
}
MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext)
{
ma_result result;
ma_context_config config;
ma_backend defaultBackends[ma_backend_null+1];
ma_uint32 iBackend;
ma_backend* pBackendsToIterate;
ma_uint32 backendsToIterateCount;
if (pContext == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pContext);
/* Always make sure the config is set first to ensure properties are available as soon as possible. */
if (pConfig != NULL) {
config = *pConfig;
} else {
config = ma_context_config_init();
}
pContext->logCallback = config.logCallback;
pContext->threadPriority = config.threadPriority;
pContext->threadStackSize = config.threadStackSize;
pContext->pUserData = config.pUserData;
result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &config.allocationCallbacks);
if (result != MA_SUCCESS) {
return result;
}
/* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */
result = ma_context_init_backend_apis(pContext);
if (result != MA_SUCCESS) {
return result;
}
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);
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
result = ma_mutex_init(&pDevice->lock);
if (result != MA_SUCCESS) {
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result);
}
/*
When the device is started, the worker thread is the one that does the actual startup of the backend device. We
use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
Each of these semaphores is released internally by the worker thread when the work is completed. The start
semaphore is also used to wake up the worker thread.
*/
result = ma_event_init(&pDevice->wakeupEvent);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result);
}
result = ma_event_init(&pDevice->startEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result);
}
result = ma_event_init(&pDevice->stopEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result);
}
result = pContext->onDeviceInit(pContext, &config, pDevice);
if (result != MA_SUCCESS) {
return result;
}
ma_device__post_init_setup(pDevice, pConfig->deviceType);
/* If the backend did not fill out a name for the device, try a generic method. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->capture.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_capture, config.capture.pDeviceID, pDevice->capture.name, sizeof(pDevice->capture.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), (config.capture.pDeviceID == NULL) ? MA_DEFAULT_CAPTURE_DEVICE_NAME : "Capture Device", (size_t)-1);
}
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
if (pDevice->playback.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_playback, config.playback.pDeviceID, pDevice->playback.name, sizeof(pDevice->playback.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), (config.playback.pDeviceID == NULL) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1);
}
}
}
/* Some backends don't require the worker thread. */
if (!ma_context_is_backend_asynchronous(pContext)) {
/* The worker thread. */
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice);
if (result != MA_SUCCESS) {
ma_device_uninit(pDevice);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result);
}
/* Wait for the worker thread to put the device into it's stopped state for real. */
ma_event_wait(&pDevice->stopEvent);
} else {
ma_device__set_state(pDevice, MA_STATE_STOPPED);
}
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "[%s]", ma_get_backend_name(pDevice->pContext->backend));
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " %s (%s)", pDevice->capture.name, "Capture");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Format: %s -> %s", ma_get_format_name(pDevice->capture.format), ma_get_format_name(pDevice->capture.internalFormat));
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channels: %d -> %d", pDevice->capture.channels, pDevice->capture.internalChannels);
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d", pDevice->sampleRate, pDevice->capture.internalSampleRate);
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalP...
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Conversion:");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Post Format Conversion: %s", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channel Routing: %s", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->capture.converter.hasResampler ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->capture.converter.isPassthrough ? "YES" : "NO");
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " %s (%s)", pDevice->playback.name, "Playback");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Format: %s -> %s", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat));
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channels: %d -> %d", pDevice->playback.channels, pDevice->playback.internalChannels);
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Sample Rate: %d -> %d", pDevice->sampleRate, pDevice->playback.internalSampleRate);
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Buffer Size: %d*%d (%d)", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.inter...
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Conversion:");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Pre Format Conversion: %s", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Post Format Conversion: %s", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Channel Routing: %s", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Resampling: %s", pDevice->playback.converter.hasResampler ? "YES" : "NO");
ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, " Passthrough: %s", pDevice->playback.converter.isPassthrough ? "YES" : "NO");
}
MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STOPPED);
return MA_SUCCESS;
}
MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice)
{
ma_result result;
ma_context* pContext;
ma_backend defaultBackends[ma_backend_null+1];
ma_uint32 iBackend;
ma_backend* pBackendsToIterate;
ma_uint32 backendsToIterateCount;
ma_allocation_callbacks allocationCallbacks;
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
} else {
allocationCallbacks = ma_allocation_callbacks_init_default();
}
pContext = (ma_context*)ma__malloc_from_callbacks(sizeof(*pContext), &allocationCallbacks);
if (pContext == NULL) {
return 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);
}
result = MA_NO_BACKEND;
for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) {
result = ma_context_init(&pBackendsToIterate[iBackend], 1, pContextConfig, pContext);
if (result == MA_SUCCESS) {
result = ma_device_init(pContext, pConfig, pDevice);
if (result == MA_SUCCESS) {
break; /* Success. */
} else {
ma_context_uninit(pContext); /* Failure. */
}
}
}
if (result != MA_SUCCESS) {
ma__free_from_callbacks(pContext, &allocationCallbacks);
return result;
}
pDevice->isOwnerOfContext = MA_TRUE;
return result;
}
MA_API void ma_device_uninit(ma_device* pDevice)
{
if (!ma_device__is_initialized(pDevice)) {
return;
}
/* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */
if (ma_device_is_started(pDevice)) {
ma_device_stop(pDevice);
}
/* Putting the device into an uninitialized state will make the worker thread return. */
ma_device__set_state(pDevice, MA_STATE_UNINITIALIZED);
/* Wake up the worker thread and wait for it to properly terminate. */
if (!ma_context_is_backend_asynchronous(pDevice->pContext)) {
ma_event_signal(&pDevice->wakeupEvent);
ma_thread_wait(&pDevice->thread);
}
pDevice->pContext->onDeviceUninit(pDevice);
ma_event_uninit(&pDevice->stopEvent);
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
if (pDevice->isOwnerOfContext) {
ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks;
ma_context_uninit(pDevice->pContext);
ma__free_from_callbacks(pDevice->pContext, &allocationCallbacks);
}
MA_ZERO_OBJECT(pDevice);
}
MA_API ma_result ma_device_start(ma_device* pDevice)
{
ma_result result;
if (pDevice == NULL) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
}
if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED);
}
if (ma_device__get_state(pDevice) == MA_STATE_STARTED) {
return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_start() called when the device is already started.", MA_INVALID_OPERATION); /* Already started. Returning an error to let the application know because it probably means they're d...
}
result = MA_ERROR;
ma_mutex_lock(&pDevice->lock);
{
/* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */
MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STOPPED);
ma_device__set_state(pDevice, MA_STATE_STARTING);
/* Asynchronous backends need to be handled differently. */
if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
result = pDevice->pContext->onDeviceStart(pDevice);
if (result == MA_SUCCESS) {
ma_device__set_state(pDevice, MA_STATE_STARTED);
}
} else {
/*
Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the
thread and then wait for the start event.
*/
ma_event_signal(&pDevice->wakeupEvent);
/*
Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device
into the started state. Don't call ma_device__set_state() here.
*/
ma_event_wait(&pDevice->startEvent);
result = pDevice->workResult;
}
}
ma_mutex_unlock(&pDevice->lock);
return result;
}
MA_API ma_result ma_device_stop(ma_device* pDevice)
{
ma_result result;
if (pDevice == NULL) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
}
if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED);
}
if (ma_device__get_state(pDevice) == MA_STATE_STOPPED) {
return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_stop() called when the device is already stopped.", MA_INVALID_OPERATION); /* Already stopped. Returning an error to let the application know because it probably means they're d...
}
result = MA_ERROR;
ma_mutex_lock(&pDevice->lock);
{
/* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STARTED);
ma_device__set_state(pDevice, MA_STATE_STOPPING);
/* There's no need to wake up the thread like we do when starting. */
if (pDevice->pContext->onDeviceStop) {
result = pDevice->pContext->onDeviceStop(pDevice);
} else {
result = MA_SUCCESS;
}
/* Asynchronous backends need to be handled differently. */
if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
ma_device__set_state(pDevice, MA_STATE_STOPPED);
} else {
/* Synchronous backends. */
/*
We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
*/
ma_event_wait(&pDevice->stopEvent);
result = MA_SUCCESS;
}
}
ma_mutex_unlock(&pDevice->lock);
return result;
}
MA_API ma_bool32 ma_device_is_started(ma_device* pDevice)
{
if (pDevice == NULL) {
return MA_FALSE;
}
return ma_device__get_state(pDevice) == MA_STATE_STARTED;
}
MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume)
{
if (pDevice == NULL) {
return MA_INVALID_ARGS;
}
if (volume < 0.0f || volume > 1.0f) {
return MA_INVALID_ARGS;
}
pDevice->masterVolumeFactor = volume;
return MA_SUCCESS;
}
MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume)
{
if (pVolume == NULL) {
return MA_INVALID_ARGS;
}
if (pDevice == NULL) {
*pVolume = 0;
return MA_INVALID_ARGS;
}
*pVolume = pDevice->masterVolumeFactor;
return MA_SUCCESS;
}
MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB)
{
if (gainDB > 0) {