view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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] |
| ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607] |
| ma_format_s32 | 32-bit signed integer | [-2147483648, 2147483647] |
| ma_format_u8 | 8-bit unsigned integer | [0, 255] |
+---------------+----------------------------------------+---------------------------+
The `config.playback.channels` member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The
`config.sampleRate` member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to
44100 or 48000, but can be set to anything. It's recommended to keep this between 8000 and 384000, however.
Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device's native configuration being used
which is useful if you want to avoid the overhead of miniaudio's automatic data conversion.
In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is
not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio
structures are transparent.
Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return
`MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop
it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again.
Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an
event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback:
```c
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
```
You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There
are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a
real-time processing thing which is beyond the scope of this introduction.
The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type
from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so:
```c
ma_device_config config = ma_device_config_init(ma_device_type_capture);
config.capture.format = MY_FORMAT;
config.capture.channels = MY_CHANNEL_COUNT;
```
In the data callback you just read from the input buffer (`pInput` in the example above) and leave the output buffer alone (it will be set to NULL when the
device type is set to `ma_device_type_capture`).
These are the available device types and how you should handle the buffers in the callback:
+-------------------------+--------------------------------------------------------+
| Device Type | Callback Behavior |
+-------------------------+--------------------------------------------------------+
| ma_device_type_playback | Write to output buffer, leave input buffer untouched. |
| ma_device_type_capture | Read from input buffer, leave output buffer untouched. |
| ma_device_type_duplex | Read from input buffer, write to output buffer. |
| ma_device_type_loopback | Read from input buffer, leave output buffer untouched. |
+-------------------------+--------------------------------------------------------+
You will notice in the example above that the sample format and channel count is specified separately for playback and capture. This is to support different
data formats between the playback and capture devices in a full-duplex system. An example may be that you want to capture audio data as a monaural stream (one
channel), but output sound to a stereo speaker system. Note that if you use different formats between playback and capture in a full-duplex configuration you
will need to convert the data yourself. There are functions available to help you do this which will be explained later.
The example above did not specify a physical device to connect to which means it will use the operating system's default device. If you have multiple physical
devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so:
```c
config.playback.pDeviceID = pMyPlaybackDeviceID; // Only if requesting a playback or duplex device.
config.capture.pDeviceID = pMyCaptureDeviceID; // Only if requesting a capture, duplex or loopback device.
```
To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept called the "context". Conceptually
speaking the context sits above the device. There is one context to many devices. The purpose of the context is to represent the backend at a more global level
and to perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing
backends and enumerating devices. The example below shows how to enumerate devices.
```c
ma_context context;
if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) {
// Error.
}
ma_device_info* pPlaybackInfos;
ma_uint32 playbackCount;
ma_device_info* pCaptureInfos;
ma_uint32 captureCount;
if (ma_context_get_devices(&context, &pPlaybackInfos, &playbackCount, &pCaptureInfos, &captureCount) != MA_SUCCESS) {
// Error.
}
// Loop over each device info and do something with it. Here we just print the name with their index. You may want
// to give the user the opportunity to choose which device they'd prefer.
for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) {
printf("%d - %s\n", iDevice, pPlaybackInfos[iDevice].name);
}
ma_device_config config = ma_device_config_init(ma_device_type_playback);
config.playback.pDeviceID = &pPlaybackInfos[chosenPlaybackDeviceIndex].id;
config.playback.format = MY_FORMAT;
config.playback.channels = MY_CHANNEL_COUNT;
config.sampleRate = MY_SAMPLE_RATE;
config.dataCallback = data_callback;
config.pUserData = pMyCustomData;
ma_device device;
if (ma_device_init(&context, &config, &device) != MA_SUCCESS) {
// Error
}
...
ma_device_uninit(&device);
ma_context_uninit(&context);
```
The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. The first parameter is a pointer to a list of `ma_backend`
values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio's default priorities are used. The second
parameter is the number of backends listed in the array pointed to by the first parameter. The third parameter is a pointer to a `ma_context_config` object
which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks,
user-defined data and some backend-specific configurations.
Once the context has been initialized you can enumerate devices. In the example above we use the simpler `ma_context_get_devices()`, however you can also use a
callback for handling devices by using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer to a pointer that will,
upon output, be set to a pointer to a buffer containing a list of `ma_device_info` structures. You also provide a pointer to an unsigned integer that will
receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio.
The `ma_device_info` structure contains an `id` member which is the ID you pass to the device config. It also contains the name of the device which is useful
for presenting a list of devices to the user via the UI.
When creating your own context you will want to pass it to `ma_device_init()` when initializing the device. Passing in NULL, like we do in the first example,
will result in miniaudio creating the context for you, which you don't want to do since you've already created a context. Note that internally the context is
only tracked by it's pointer which means you must not change the location of the `ma_context` object. If this is an issue, consider using `malloc()` to
allocate memory for the context.
2. Building
===========
miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details.
2.1. Windows
------------
The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries.
2.2. macOS and iOS
------------------
The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be
compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling through the command line
requires linking to `-lpthread` and `-lm`.
Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's notarization process. To fix this there are two options. The
first is to use the `MA_NO_RUNTIME_LINKING` option, like so:
```c
#ifdef __APPLE__
#define MA_NO_RUNTIME_LINKING
#endif
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
```
This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. Alternatively, if you would rather keep using runtime
linking you can add the following to your entitlements.xcent file:
```
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
```
2.3. Linux
----------
The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any development packages.
2.4. BSD
--------
The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS.
2.5. Android
------------
AAudio is the highest priority backend on Android. This should work out of the box without needing any kind of compiler configuration. Support for AAudio
starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+.
2.6. Emscripten
---------------
The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use -std=c* compiler flags, nor -ansi.
2.7. Build Options
------------------
`#define` these options before including miniaudio.h.
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| Option | Description |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_WASAPI | Disables the WASAPI backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_DSOUND | Disables the DirectSound backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_WINMM | Disables the WinMM backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_ALSA | Disables the ALSA backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_PULSEAUDIO | Disables the PulseAudio backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_JACK | Disables the JACK backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_COREAUDIO | Disables the Core Audio backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_SNDIO | Disables the sndio backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_AUDIO4 | Disables the audio(4) backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_OSS | Disables the OSS backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_AAUDIO | Disables the AAudio backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_OPENSL | Disables the OpenSL|ES backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_WEBAUDIO | Disables the Web Audio backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_NULL | Disables the null backend. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_DECODING | Disables decoding APIs. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_ENCODING | Disables encoding APIs. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_WAV | Disables the built-in WAV decoder and encoder. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_FLAC | Disables the built-in FLAC decoder. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_MP3 | Disables the built-in MP3 decoder. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_DEVICE_IO | Disables playback and recording. This will disable ma_context and ma_device APIs. This is useful if you only want to use |
| | miniaudio's data conversion and/or decoding APIs. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_THREADING | Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs. This option is useful if you only need to use miniaudio for |
| | data conversion, decoding and/or encoding. Some families of APIs require threading which means the following options must also |
| | be set: |
| | |
| | ``` |
| | MA_NO_DEVICE_IO |
| | ``` |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_GENERATION | Disables generation APIs such a ma_waveform and ma_noise. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_SSE2 | Disables SSE2 optimizations. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_AVX2 | Disables AVX2 optimizations. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_AVX512 | Disables AVX-512 optimizations. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_NO_NEON | Disables NEON optimizations. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_LOG_LEVEL [level] | Sets the logging level. Set level to one of the following: |
| | |
| | ``` |
| | MA_LOG_LEVEL_VERBOSE |
| | MA_LOG_LEVEL_INFO |
| | MA_LOG_LEVEL_WARNING |
| | MA_LOG_LEVEL_ERROR |
| | ``` |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_DEBUG_OUTPUT | Enable printf() debug output. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_COINIT_VALUE | Windows only. The value to pass to internal calls to `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_API | Controls how public APIs should be decorated. Defaults to `extern`. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
| MA_DLL | If set, configures MA_API to either import or export APIs depending on whether or not the implementation is being defined. If |
| | defining the implementation, MA_API will be configured to export. Otherwise it will be configured to import. This has no effect |
| | if MA_API is defined externally. |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------+
3. Definitions
==============
This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this
section is intended to clarify how miniaudio uses each term.
3.1. Sample
-----------
A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number.
3.2. Frame / PCM Frame
----------------------
A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame
is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio
needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame".
3.3. Channel
------------
A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A
stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as
a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and
should not be confused.
3.4. Sample Rate
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
```c
void* pMappedFrames;
ma_uint64 frameCount = frameCountToTryMapping;
ma_result result = ma_audio_buffer_map(pAudioBuffer, &pMappedFrames, &frameCount);
if (result == MA_SUCCESS) {
// Map was successful. The value in frameCount will be how many frames were _actually_ mapped, which may be
// less due to the end of the buffer being reached.
ma_copy_pcm_frames(pFramesOut, pMappedFrames, frameCount, pAudioBuffer->format, pAudioBuffer->channels);
// You must unmap the buffer.
ma_audio_buffer_unmap(pAudioBuffer, frameCount);
}
```
When you use memory mapping, the read cursor is increment by the frame count passed in to `ma_audio_buffer_unmap()`. If you decide not to process every frame
you can pass in a value smaller than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is that it does not handle looping
for you. You can determine if the buffer is at the end for the purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of
`ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` as an error when returned by `ma_audio_buffer_unmap()`.
10. Ring Buffers
================
miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates
on bytes, whereas the `ma_pcm_rb` operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around `ma_rb`.
Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for
the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for you.
The examples below use the PCM frame variant of the ring buffer since that's most likely the one you will want to use. To initialize a ring buffer, do
something like the following:
```c
ma_pcm_rb rb;
ma_result result = ma_pcm_rb_init(FORMAT, CHANNELS, BUFFER_SIZE_IN_FRAMES, NULL, NULL, &rb);
if (result != MA_SUCCESS) {
// Error
}
```
The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because it's the PCM varient of the ring buffer API. For the regular
ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The
fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation
routines. Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used.
Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your
sub-buffers you can use `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and `ma_pcm_rb_get_subbuffer_ptr()`.
Use 'ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you
need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require
a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested.
After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or
`ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier
call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and
`ma_pcm_rb_commit_write()` is what's used to increment the pointers.
If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`,
`ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via
the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If
there is too little space between the pointers, move the write pointer forward.
You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the same, only you will use the `ma_rb`
functions instead of `ma_pcm_rb` and instead of frame counts you will pass around byte counts.
The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most significant bit being used to encode a loop flag and the internally
managed buffers always being aligned to MA_SIMD_ALIGNMENT.
Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread.
11. Backends
============
The following backends are supported by miniaudio.
+-------------+-----------------------+--------------------------------------------------------+
| Name | Enum Name | Supported Operating Systems |
+-------------+-----------------------+--------------------------------------------------------+
| WASAPI | ma_backend_wasapi | Windows Vista+ |
| DirectSound | ma_backend_dsound | Windows XP+ |
| WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) |
| Core Audio | ma_backend_coreaudio | macOS, iOS |
| ALSA | ma_backend_alsa | Linux |
| PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) |
| JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) |
| sndio | ma_backend_sndio | OpenBSD |
| audio(4) | ma_backend_audio4 | NetBSD, OpenBSD |
| OSS | ma_backend_oss | FreeBSD |
| AAudio | ma_backend_aaudio | Android 8+ |
| OpenSL ES | ma_backend_opensl | Android (API level 16+) |
| Web Audio | ma_backend_webaudio | Web (via Emscripten) |
| Null | ma_backend_null | Cross Platform (not used on Web) |
+-------------+-----------------------+--------------------------------------------------------+
Some backends have some nuance details you may want to be aware of.
11.1. WASAPI
------------
- Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device's native sample rate. To work around
this, set `wasapi.noAutoConvertSRC` to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the
`AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio's internal resampler being used instead
which will in turn enable the use of low-latency shared mode.
11.2. PulseAudio
----------------
- If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki:
https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. Alternatively, consider using a different backend such as ALSA.
11.3. Android
-------------
- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: `<uses-permission android:name="android.permission.RECORD_AUDIO" />`
- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES.
- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however
perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init().
- The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any
potential device-specific optimizations the driver may implement.
11.4. UWP
---------
- UWP only supports default playback and capture devices.
- UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest):
```
<Package ...>
...
<Capabilities>
<DeviceCapability Name="microphone" />
</Capabilities>
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects.
- Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated.
- Google has implemented a policy in their browsers that prevent automatic media output without first receiving some kind of user input. The following web page
has additional details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback
without first handling some kind of user input.
12. Miscellaneous Notes
=======================
- Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as
PulseAudio may naturally support it, though not all have been tested.
- The contents of the output buffer passed into the data callback will always be pre-initialized to zero unless the `noPreZeroedOutputBuffer` config variable
in `ma_device_config` is set to true, in which case it'll be undefined which will require you to write something to the entire buffer.
- By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as `ma_format_f32`. If you are doing
clipping yourself, you can disable this overhead by setting `noClip` to true in the device config.
- The sndio backend is currently only enabled on OpenBSD builds.
- The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it.
- Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations.
- When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available.
*/
#ifndef miniaudio_h
#define miniaudio_h
#ifdef __cplusplus
extern "C" {
#endif
#define MA_STRINGIFY(x) #x
#define MA_XSTRINGIFY(x) MA_STRINGIFY(x)
#define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 10
#define MA_VERSION_REVISION 21
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */
#pragma warning(disable:4214) /* nonstandard extension used: bit field types other than int */
#pragma warning(disable:4324) /* structure was padded due to alignment specifier */
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */
#endif
#endif
/* Platform/backend detection. */
#ifdef _WIN32
#define MA_WIN32
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#define MA_WIN32_UWP
#else
#define MA_WIN32_DESKTOP
#endif
#else
#define MA_POSIX
#include <pthread.h> /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
#ifdef __unix__
#define MA_UNIX
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_BSD
#endif
#endif
#ifdef __linux__
#define MA_LINUX
#endif
#ifdef __APPLE__
#define MA_APPLE
#endif
#ifdef __ANDROID__
#define MA_ANDROID
#endif
#ifdef __EMSCRIPTEN__
#define MA_EMSCRIPTEN
#endif
#endif
#include <stddef.h> /* For size_t. */
/* Sized types. */
typedef signed char ma_int8;
typedef unsigned char ma_uint8;
typedef signed short ma_int16;
typedef unsigned short ma_uint16;
typedef signed int ma_int32;
typedef unsigned int ma_uint32;
#if defined(_MSC_VER)
typedef signed __int64 ma_int64;
typedef unsigned __int64 ma_uint64;
#else
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc++11-long-long"
#endif
#endif
typedef signed long long ma_int64;
typedef unsigned long long ma_uint64;
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#endif
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
typedef ma_uint64 ma_uintptr;
#else
typedef ma_uint32 ma_uintptr;
#endif
typedef ma_uint8 ma_bool8;
typedef ma_uint32 ma_bool32;
#define MA_TRUE 1
#define MA_FALSE 0
typedef void* ma_handle;
typedef void* ma_ptr;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
typedef enum
{
/*
I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample().
*/
ma_format_unknown = 0, /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */
ma_format_u8 = 1,
ma_format_s16 = 2, /* Seems to be the most widely supported format. */
ma_format_s24 = 3, /* Tightly packed. 3 bytes per sample. */
ma_format_s32 = 4,
ma_format_f32 = 5,
ma_format_count
} ma_format;
typedef enum
{
ma_channel_mix_mode_rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */
ma_channel_mix_mode_simple, /* Drop excess channels; zeroed out extra channels. */
ma_channel_mix_mode_custom_weights, /* Use custom weights specified in ma_channel_router_config. */
ma_channel_mix_mode_planar_blend = ma_channel_mix_mode_rectangular,
ma_channel_mix_mode_default = ma_channel_mix_mode_planar_blend
} ma_channel_mix_mode;
typedef enum
{
ma_standard_channel_map_microsoft,
ma_standard_channel_map_alsa,
ma_standard_channel_map_rfc3551, /* Based off AIFF. */
ma_standard_channel_map_flac,
ma_standard_channel_map_vorbis,
ma_standard_channel_map_sound4, /* FreeBSD's sound(4). */
ma_standard_channel_map_sndio, /* www.sndio.org/tips.html */
ma_standard_channel_map_webaudio = ma_standard_channel_map_flac, /* https://webaudio.github.io/web-audio-api/#ChannelOrdering. Only 1, 2, 4 and 6 channels are defined, but can fill in the gaps with logical assumptions. */
ma_standard_channel_map_default = ma_standard_channel_map_microsoft
} ma_standard_channel_map;
typedef enum
{
ma_performance_profile_low_latency = 0,
ma_performance_profile_conservative
} ma_performance_profile;
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} ma_allocation_callbacks;
typedef struct
{
ma_int32 state;
} ma_lcg;
#ifndef MA_NO_THREADING
/* Thread priorties should be ordered such that the default priority of the worker thread is 0. */
typedef enum
{
ma_thread_priority_idle = -5,
ma_thread_priority_lowest = -4,
ma_thread_priority_low = -3,
ma_thread_priority_normal = -2,
ma_thread_priority_high = -1,
ma_thread_priority_highest = 0,
ma_thread_priority_realtime = 1,
ma_thread_priority_default = 0
} ma_thread_priority;
typedef unsigned char ma_spinlock;
#if defined(MA_WIN32)
typedef ma_handle ma_thread;
#endif
#if defined(MA_POSIX)
typedef pthread_t ma_thread;
#endif
#if defined(MA_WIN32)
typedef ma_handle ma_mutex;
#endif
#if defined(MA_POSIX)
typedef pthread_mutex_t ma_mutex;
#endif
#if defined(MA_WIN32)
typedef ma_handle ma_event;
#endif
#if defined(MA_POSIX)
typedef struct
{
ma_uint32 value;
pthread_mutex_t lock;
pthread_cond_t cond;
} ma_event;
#endif /* MA_POSIX */
#if defined(MA_WIN32)
typedef ma_handle ma_semaphore;
#endif
#if defined(MA_POSIX)
typedef struct
{
int value;
pthread_mutex_t lock;
pthread_cond_t cond;
} ma_semaphore;
#endif /* MA_POSIX */
#else
/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif /* MA_NO_THREADING */
/*
Retrieves the version of miniaudio as separated integers. Each component can be NULL if it's not required.
*/
MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision);
/*
Retrieves the version of miniaudio as a string which can be useful for logging purposes.
*/
MA_API const char* ma_version_string(void);
/**************************************************************************************************************************************************************
Biquad Filtering
**************************************************************************************************************************************************************/
typedef union
{
float f32;
ma_int32 s32;
} ma_biquad_coefficient;
typedef struct
{
ma_format format;
ma_uint32 channels;
double b0;
double b1;
double b2;
double a0;
double a1;
double a2;
} ma_biquad_config;
MA_API ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double b0, double b1, double b2, double a0, double a1, double a2);
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_biquad_coefficient b0;
ma_biquad_coefficient b1;
ma_biquad_coefficient b2;
ma_biquad_coefficient a1;
ma_biquad_coefficient a2;
ma_biquad_coefficient r1[MA_MAX_CHANNELS];
ma_biquad_coefficient r2[MA_MAX_CHANNELS];
} ma_biquad;
MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ);
MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ);
MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
MA_API ma_uint32 ma_biquad_get_latency(ma_biquad* pBQ);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ma_get_bytes_per_sample(format) * channels; }
/*
Converts a log level to a string.
*/
MA_API const char* ma_log_level_to_string(ma_uint32 logLevel);
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
DEVICE I/O
==========
This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc.
*************************************************************************************************************************************************************
************************************************************************************************************************************************************/
#ifndef MA_NO_DEVICE_IO
/* Some backends are only supported on certain platforms. */
#if defined(MA_WIN32)
#define MA_SUPPORT_WASAPI
#if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */
#define MA_SUPPORT_DSOUND
#define MA_SUPPORT_WINMM
#define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
#endif
#endif
#if defined(MA_UNIX)
#if defined(MA_LINUX)
#if !defined(MA_ANDROID) /* ALSA is not supported on Android. */
#define MA_SUPPORT_ALSA
#endif
#endif
#if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_PULSEAUDIO
#define MA_SUPPORT_JACK
#endif
#if defined(MA_ANDROID)
#define MA_SUPPORT_AAUDIO
#define MA_SUPPORT_OPENSL
#endif
#if defined(__OpenBSD__) /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */
#define MA_SUPPORT_SNDIO /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
#define MA_SUPPORT_AUDIO4 /* Only support audio(4) on platforms with known support. */
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__)
#define MA_SUPPORT_OSS /* Only support OSS on specific platforms with known support. */
#endif
#endif
#if defined(MA_APPLE)
#define MA_SUPPORT_COREAUDIO
#endif
#if defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_WEBAUDIO
#endif
/* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
#if !defined(MA_EMSCRIPTEN)
#define MA_SUPPORT_NULL
#endif
#if !defined(MA_NO_WASAPI) && defined(MA_SUPPORT_WASAPI)
#define MA_ENABLE_WASAPI
#endif
#if !defined(MA_NO_DSOUND) && defined(MA_SUPPORT_DSOUND)
#define MA_ENABLE_DSOUND
#endif
#if !defined(MA_NO_WINMM) && defined(MA_SUPPORT_WINMM)
#define MA_ENABLE_WINMM
#endif
#if !defined(MA_NO_ALSA) && defined(MA_SUPPORT_ALSA)
#define MA_ENABLE_ALSA
#endif
#if !defined(MA_NO_PULSEAUDIO) && defined(MA_SUPPORT_PULSEAUDIO)
#define MA_ENABLE_PULSEAUDIO
#endif
#if !defined(MA_NO_JACK) && defined(MA_SUPPORT_JACK)
#define MA_ENABLE_JACK
#endif
#if !defined(MA_NO_COREAUDIO) && defined(MA_SUPPORT_COREAUDIO)
#define MA_ENABLE_COREAUDIO
#endif
#if !defined(MA_NO_SNDIO) && defined(MA_SUPPORT_SNDIO)
#define MA_ENABLE_SNDIO
#endif
#if !defined(MA_NO_AUDIO4) && defined(MA_SUPPORT_AUDIO4)
#define MA_ENABLE_AUDIO4
#endif
#if !defined(MA_NO_OSS) && defined(MA_SUPPORT_OSS)
#define MA_ENABLE_OSS
#endif
#if !defined(MA_NO_AAUDIO) && defined(MA_SUPPORT_AAUDIO)
#define MA_ENABLE_AAUDIO
#endif
#if !defined(MA_NO_OPENSL) && defined(MA_SUPPORT_OPENSL)
#define MA_ENABLE_OPENSL
#endif
#if !defined(MA_NO_WEBAUDIO) && defined(MA_SUPPORT_WEBAUDIO)
#define MA_ENABLE_WEBAUDIO
#endif
#if !defined(MA_NO_NULL) && defined(MA_SUPPORT_NULL)
#define MA_ENABLE_NULL
#endif
#ifdef MA_SUPPORT_WASAPI
/* We need a IMMNotificationClient object for WASAPI. */
typedef struct
{
void* lpVtbl;
ma_uint32 counter;
ma_device* pDevice;
} ma_IMMNotificationClient;
#endif
/* Backend enums must be in priority order. */
typedef enum
{
ma_backend_wasapi,
ma_backend_dsound,
ma_backend_winmm,
ma_backend_coreaudio,
ma_backend_sndio,
ma_backend_audio4,
ma_backend_oss,
ma_backend_pulseaudio,
ma_backend_alsa,
ma_backend_jack,
ma_backend_aaudio,
ma_backend_opensl,
ma_backend_webaudio,
ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
} ma_backend;
#define MA_BACKEND_COUNT (ma_backend_null+1)
/*
The callback for processing audio data from the device.
The data callback is fired by miniaudio whenever the device needs to have more data delivered to a playback device, or when a capture device has some data
available. This is called as soon as the backend asks for more data which means it may be called with inconsistent frame counts. You cannot assume the
callback will be fired with a consistent frame count.
Parameters
----------
pDevice (in)
A pointer to the relevant device.
pOutput (out)
A pointer to the output buffer that will receive audio data that will later be played back through the speakers. This will be non-null for a playback or
full-duplex device and null for a capture and loopback device.
pInput (in)
A pointer to the buffer containing input data from a recording device. This will be non-null for a capture, full-duplex or loopback device and null for a
playback device.
frameCount (in)
The number of PCM frames to process. Note that this will not necessarily be equal to what you requested when you initialized the device. The
`periodSizeInFrames` and `periodSizeInMilliseconds` members of the device config are just hints, and are not necessarily exactly what you'll get. You must
not assume this will always be the same value each time the callback is fired.
Remarks
-------
You cannot stop and start the device from inside the callback or else you'll get a deadlock. You must also not uninitialize the device from inside the
callback. The following APIs cannot be called from inside the callback:
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
*/
typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
/*
The callback for when the device has been stopped.
This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces
such as being unplugged or an internal error occuring.
Parameters
----------
pDevice (in)
A pointer to the device that has just stopped.
Remarks
-------
Do not restart or uninitialize the device from the callback.
*/
typedef void (* ma_stop_proc)(ma_device* pDevice);
/*
The callback for handling log messages.
Parameters
----------
pContext (in)
A pointer to the context the log message originated from.
pDevice (in)
A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context.
logLevel (in)
The log level. This can be one of the following:
|----------------------|
| Log Level |
|----------------------|
| MA_LOG_LEVEL_VERBOSE |
| MA_LOG_LEVEL_INFO |
| MA_LOG_LEVEL_WARNING |
| MA_LOG_LEVEL_ERROR |
|----------------------|
message (in)
The log message.
Remarks
-------
Do not modify the state of the device from inside the callback.
*/
typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message);
typedef enum
{
ma_device_type_playback = 1,
ma_device_type_capture = 2,
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_uint32 periods;
ma_performance_profile performanceProfile;
ma_bool32 noPreZeroedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
ma_bool32 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
ma_device_callback_proc dataCallback;
ma_stop_proc stopCallback;
void* pUserData;
struct
{
ma_resample_algorithm algorithm;
struct
{
ma_uint32 lpfOrder;
} linear;
struct
{
int quality;
} speex;
} resampling;
struct
{
const ma_device_id* pDeviceID;
ma_format format;
ma_uint32 channels;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_share_mode shareMode;
} playback;
struct
{
const ma_device_id* pDeviceID;
ma_format format;
ma_uint32 channels;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_share_mode shareMode;
} capture;
struct
{
ma_bool32 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
ma_bool32 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
ma_bool32 noAutoStreamRouting; /* Disables automatic stream routing. */
ma_bool32 noHardwareOffloading; /* Disables WASAPI's hardware offloading feature. */
} wasapi;
struct
{
ma_bool32 noMMap; /* Disables MMap mode. */
ma_bool32 noAutoFormat; /* Opens the ALSA device with SND_PCM_NO_AUTO_FORMAT. */
ma_bool32 noAutoChannels; /* Opens the ALSA device with SND_PCM_NO_AUTO_CHANNELS. */
ma_bool32 noAutoResample; /* Opens the ALSA device with SND_PCM_NO_AUTO_RESAMPLE. */
} alsa;
struct
{
const char* pStreamNamePlayback;
const char* pStreamNameCapture;
} pulse;
} ma_device_config;
typedef struct
{
ma_log_proc logCallback;
ma_thread_priority threadPriority;
size_t threadStackSize;
void* pUserData;
ma_allocation_callbacks allocationCallbacks;
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
{
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_proc AAudioStream_getBufferCapacityInFrames;
ma_proc AAudioStream_getFramesPerDataCallback;
ma_proc AAudioStream_getFramesPerBurst;
ma_proc AAudioStream_requestStart;
ma_proc AAudioStream_requestStop;
} aaudio;
#endif
#ifdef MA_SUPPORT_OPENSL
struct
{
ma_handle libOpenSLES;
ma_handle SL_IID_ENGINE;
ma_handle SL_IID_AUDIOIODEVICECAPABILITIES;
ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
ma_handle SL_IID_RECORD;
ma_handle SL_IID_PLAY;
ma_handle SL_IID_OUTPUTMIX;
ma_proc slCreateEngine;
} opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
struct
{
int _unused;
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
int _unused;
} null_backend;
#endif
};
union
{
#ifdef MA_WIN32
struct
{
/*HMODULE*/ ma_handle hOle32DLL;
ma_proc CoInitializeEx;
ma_proc CoUninitialize;
ma_proc CoCreateInstance;
ma_proc CoTaskMemFree;
ma_proc PropVariantClear;
ma_proc StringFromGUID2;
/*HMODULE*/ ma_handle hUser32DLL;
ma_proc GetForegroundWindow;
ma_proc GetDesktopWindow;
/*HMODULE*/ ma_handle hAdvapi32DLL;
ma_proc RegOpenKeyExA;
ma_proc RegCloseKey;
ma_proc RegQueryValueExA;
} win32;
#endif
#ifdef MA_POSIX
struct
{
ma_handle pthreadSO;
ma_proc pthread_create;
ma_proc pthread_join;
ma_proc pthread_mutex_init;
ma_proc pthread_mutex_destroy;
ma_proc pthread_mutex_lock;
ma_proc pthread_mutex_unlock;
ma_proc pthread_cond_init;
ma_proc pthread_cond_destroy;
ma_proc pthread_cond_wait;
ma_proc pthread_cond_signal;
ma_proc pthread_attr_init;
ma_proc pthread_attr_destroy;
ma_proc pthread_attr_setschedpolicy;
ma_proc pthread_attr_getschedparam;
ma_proc pthread_attr_setschedparam;
} posix;
#endif
int _unused;
};
};
struct ma_device
{
ma_context* pContext;
ma_device_type type;
ma_uint32 sampleRate;
volatile ma_uint32 state; /* The state of the device is variable and can change at any time on any thread, so tell the compiler as such with `volatile`. */
ma_device_callback_proc onData; /* Set once at initialization time and should not be changed after. */
ma_stop_proc onStop; /* Set once at initialization time and should not be changed after. */
void* pUserData; /* Application defined data. */
ma_mutex lock;
ma_event wakeupEvent;
ma_event startEvent;
ma_event stopEvent;
ma_thread thread;
ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */
ma_bool32 usingDefaultSampleRate : 1;
ma_bool32 usingDefaultBufferSize : 1;
ma_bool32 usingDefaultPeriods : 1;
ma_bool32 isOwnerOfContext : 1; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
ma_bool32 noPreZeroedOutputBuffer : 1;
ma_bool32 noClip : 1;
volatile float masterVolumeFactor; /* Volatile so we can use some thread safety when applying volume to periods. */
struct
{
ma_resample_algorithm algorithm;
struct
{
ma_uint32 lpfOrder;
} linear;
struct
{
int quality;
} speex;
} resampling;
struct
{
ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */
ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
ma_bool32 usingDefaultFormat : 1;
ma_bool32 usingDefaultChannels : 1;
ma_bool32 usingDefaultChannelMap : 1;
ma_format format;
ma_uint32 channels;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_format internalFormat;
ma_uint32 internalChannels;
ma_uint32 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_uint32 internalPeriodSizeInFrames;
ma_uint32 internalPeriods;
ma_data_converter converter;
} playback;
struct
{
ma_device_id id; /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */
ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
ma_bool32 usingDefaultFormat : 1;
ma_bool32 usingDefaultChannels : 1;
ma_bool32 usingDefaultChannelMap : 1;
ma_format format;
ma_uint32 channels;
ma_channel channelMap[MA_MAX_CHANNELS];
ma_format internalFormat;
ma_uint32 internalChannels;
ma_uint32 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_uint32 internalPeriodSizeInFrames;
ma_uint32 internalPeriods;
ma_data_converter converter;
} capture;
union
{
#ifdef MA_SUPPORT_WASAPI
struct
{
/*IAudioClient**/ ma_ptr pAudioClientPlayback;
/*IAudioClient**/ ma_ptr pAudioClientCapture;
/*IAudioRenderClient**/ ma_ptr pRenderClient;
/*IAudioCaptureClient**/ ma_ptr pCaptureClient;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
ma_ptr handlePlayback;
ma_ptr handleCapture;
ma_bool32 isStartedPlayback;
ma_bool32 isStartedCapture;
} sndio;
#endif
#ifdef MA_SUPPORT_AUDIO4
struct
{
int fdPlayback;
int fdCapture;
} audio4;
#endif
#ifdef MA_SUPPORT_OSS
struct
{
int fdPlayback;
int fdCapture;
} oss;
#endif
#ifdef MA_SUPPORT_AAUDIO
struct
{
/*AAudioStream**/ ma_ptr pStreamPlayback;
/*AAudioStream**/ ma_ptr pStreamCapture;
ma_pcm_rb duplexRB;
} aaudio;
#endif
#ifdef MA_SUPPORT_OPENSL
struct
{
/*SLObjectItf*/ ma_ptr pOutputMixObj;
/*SLOutputMixItf*/ ma_ptr pOutputMix;
/*SLObjectItf*/ ma_ptr pAudioPlayerObj;
/*SLPlayItf*/ ma_ptr pAudioPlayer;
/*SLObjectItf*/ ma_ptr pAudioRecorderObj;
/*SLRecordItf*/ ma_ptr pAudioRecorder;
/*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
/*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
ma_bool32 isDrainingCapture;
ma_bool32 isDrainingPlayback;
ma_uint32 currentBufferIndexPlayback;
ma_uint32 currentBufferIndexCapture;
ma_uint8* pBufferPlayback; /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
ma_uint8* pBufferCapture;
ma_pcm_rb duplexRB;
} opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
struct
{
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexCapture;
ma_pcm_rb duplexRB; /* In external capture format. */
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_uint32 operation;
ma_result operationResult;
ma_timer timer;
double priorRunTime;
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint64 lastProcessedFrameCapture;
ma_bool32 isStarted;
} null_device;
#endif
};
};
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#else
#pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#endif
/*
Initializes a `ma_context_config` object.
Return Value
------------
A `ma_context_config` initialized to defaults.
Remarks
-------
You must always use this to initialize the default state of the `ma_context_config` object. Not using this will result in your program breaking when miniaudio
is updated and new members are added to `ma_context_config`. It also sets logical defaults.
You can override members of the returned object by changing it's members directly.
See Also
--------
ma_context_init()
*/
MA_API ma_context_config ma_context_config_init(void);
/*
Initializes a context.
The context is used for selecting and initializing an appropriate backend and to represent the backend at a more global level than that of an individual
device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices.
Parameters
----------
backends (in, optional)
A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
backendCount (in, optional)
The number of items in `backend`. Ignored if `backend` is NULL.
pConfig (in, optional)
The context configuration.
pContext (in)
A pointer to the context object being initialized.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
|-------------|-----------------------|--------------------------------------------------------|
| Name | Enum Name | Supported Operating Systems |
|-------------|-----------------------|--------------------------------------------------------|
| WASAPI | ma_backend_wasapi | Windows Vista+ |
| DirectSound | ma_backend_dsound | Windows XP+ |
| WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) |
| Core Audio | ma_backend_coreaudio | macOS, iOS |
| ALSA | ma_backend_alsa | Linux |
| PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) |
| JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) |
| sndio | ma_backend_sndio | OpenBSD |
| audio(4) | ma_backend_audio4 | NetBSD, OpenBSD |
| OSS | ma_backend_oss | FreeBSD |
| AAudio | ma_backend_aaudio | Android 8+ |
| OpenSL|ES | ma_backend_opensl | Android (API level 16+) |
| Web Audio | ma_backend_webaudio | Web (via Emscripten) |
| Null | ma_backend_null | Cross Platform (not used on Web) |
|-------------|-----------------------|--------------------------------------------------------|
The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings
can then be set directly on the structure. Below are the members of the `ma_context_config` object.
logCallback
Callback for handling log messages from miniaudio.
threadPriority
The desired priority to use for the audio thread. Allowable values include the following:
|--------------------------------------|
| Thread Priority |
|--------------------------------------|
| ma_thread_priority_idle |
| ma_thread_priority_lowest |
| ma_thread_priority_low |
| ma_thread_priority_normal |
| ma_thread_priority_high |
| ma_thread_priority_highest (default) |
| ma_thread_priority_realtime |
| ma_thread_priority_default |
|--------------------------------------|
pUserData
A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`.
allocationCallbacks
Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation
callbacks will be used for anything tied to the context, including devices.
alsa.useVerboseDeviceEnumeration
ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique
card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes
it so the ALSA backend includes all devices. Defaults to false.
pulse.pApplicationName
PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`.
pulse.pServerName
PulseAudio only. The name of the server to connect to with `pa_context_connect()`.
pulse.tryAutoSpawn
PulseAudio only. Whether or not to try automatically starting the PulseAudio daemon. Defaults to false. If you set this to true, keep in mind that
miniaudio uses a trial and error method to find the most appropriate backend, and this will result in the PulseAudio daemon starting which may be
intrusive for the end user.
coreaudio.sessionCategory
iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
|-----------------------------------------|-------------------------------------|
| miniaudio Token | Core Audio Token |
|-----------------------------------------|-------------------------------------|
| ma_ios_session_category_ambient | AVAudioSessionCategoryAmbient |
| ma_ios_session_category_solo_ambient | AVAudioSessionCategorySoloAmbient |
| ma_ios_session_category_playback | AVAudioSessionCategoryPlayback |
| ma_ios_session_category_record | AVAudioSessionCategoryRecord |
| ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord |
| ma_ios_session_category_multi_route | AVAudioSessionCategoryMultiRoute |
| ma_ios_session_category_none | AVAudioSessionCategoryAmbient |
| ma_ios_session_category_default | AVAudioSessionCategoryAmbient |
|-----------------------------------------|-------------------------------------|
coreaudio.sessionCategoryOptions
iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
|---------------------------------------------------------------------------|------------------------------------------------------------------|
| miniaudio Token | Core Audio Token |
|---------------------------------------------------------------------------|------------------------------------------------------------------|
| ma_ios_session_category_option_mix_with_others | AVAudioSessionCategoryOptionMixWithOthers |
| ma_ios_session_category_option_duck_others | AVAudioSessionCategoryOptionDuckOthers |
| ma_ios_session_category_option_allow_bluetooth | AVAudioSessionCategoryOptionAllowBluetooth |
| ma_ios_session_category_option_default_to_speaker | AVAudioSessionCategoryOptionDefaultToSpeaker |
| ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
| ma_ios_session_category_option_allow_bluetooth_a2dp | AVAudioSessionCategoryOptionAllowBluetoothA2DP |
| ma_ios_session_category_option_allow_air_play | AVAudioSessionCategoryOptionAllowAirPlay |
|---------------------------------------------------------------------------|------------------------------------------------------------------|
jack.pClientName
The name of the client to pass to `jack_client_open()`.
jack.tryStartServer
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
The example below shows how to initialize the context using the default configuration.
```c
ma_context context;
ma_result result = ma_context_init(NULL, 0, NULL, &context);
if (result != MA_SUCCESS) {
// Error.
}
```
Example 2 - Custom Configuration
--------------------------------
The example below shows how to initialize the context using custom backend priorities and a custom configuration. In this hypothetical example, the program
wants to prioritize ALSA over PulseAudio on Linux. They also want to avoid using the WinMM backend on Windows because it's latency is too high. They also
want an error to be returned if no valid backend is available which they achieve by excluding the Null backend.
For the configuration, the program wants to capture any log messages so they can, for example, route it to a log file and user interface.
```c
ma_backend backends[] = {
ma_backend_alsa,
ma_backend_pulseaudio,
ma_backend_wasapi,
ma_backend_dsound
};
ma_context_config config = ma_context_config_init();
config.logCallback = my_log_callback;
config.pUserData = pMyUserData;
ma_context context;
ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context);
if (result != MA_SUCCESS) {
// Error.
if (result == MA_NO_BACKEND) {
// Couldn't find an appropriate backend.
}
}
```
See Also
--------
ma_context_config_init()
ma_context_uninit()
*/
MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext);
/*
Uninitializes a context.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
Results are undefined if you call this while any device created by this context is still active.
See Also
--------
ma_context_init()
*/
MA_API ma_result ma_context_uninit(ma_context* pContext);
/*
Retrieves the size of the ma_context object.
This is mainly for the purpose of bindings to know how much memory to allocate.
*/
MA_API size_t ma_context_sizeof(void);
/*
Enumerates over every device (both playback and capture).
This is a lower-level enumeration function to the easier to use `ma_context_get_devices()`. Use `ma_context_enumerate_devices()` if you would rather not incur
an internal heap allocation, or it simply suits your code better.
Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require
opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using `ma_context_get_device_info()` for this,
but don't call it from within the enumeration callback.
Returning false from the callback will stop enumeration. Returning true will continue enumeration.
Parameters
----------
pContext (in)
A pointer to the context performing the enumeration.
callback (in)
The callback to fire for each enumerated device.
pUserData (in)
A pointer to application-defined data passed to the callback.
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_ assume the first enumerated device of a given type is the default device.
Some backends and platforms may only support default playback and capture devices.
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
capture.channelMap
The channel map to use for capture. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the
device object direct with `device.capture.channelMap`.
capture.shareMode
The preferred share mode to use for capture. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify
exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to
ma_share_mode_shared and reinitializing.
wasapi.noAutoConvertSRC
WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false.
wasapi.noDefaultQualitySRC
WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`.
You should usually leave this set to false, which is the default.
wasapi.noAutoStreamRouting
WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false.
wasapi.noHardwareOffloading
WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false.
alsa.noMMap
ALSA only. When set to true, disables MMap mode. Defaults to false.
alsa.noAutoFormat
ALSA only. When set to true, disables ALSA's automatic format conversion by including the SND_PCM_NO_AUTO_FORMAT flag. Defaults to false.
alsa.noAutoChannels
ALSA only. When set to true, disables ALSA's automatic channel conversion by including the SND_PCM_NO_AUTO_CHANNELS flag. Defaults to false.
alsa.noAutoResample
ALSA only. When set to true, disables ALSA's automatic resampling by including the SND_PCM_NO_AUTO_RESAMPLE flag. Defaults to false.
pulse.pStreamNamePlayback
PulseAudio only. Sets the stream name for playback.
pulse.pStreamNameCapture
PulseAudio only. Sets the stream name for capture.
Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
After initializing the device it will be in a stopped state. To start it, use `ma_device_start()`.
If both `periodSizeInFrames` and `periodSizeInMilliseconds` are set to zero, it will default to `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY` or
`MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE`, depending on whether or not `performanceProfile` is set to `ma_performance_profile_low_latency` or
`ma_performance_profile_conservative`.
If you request exclusive mode and the backend does not support it an error will be returned. For robustness, you may want to first try initializing the device
in exclusive mode, and then fall back to shared mode if required. Alternatively you can just request shared mode (the default if you leave it unset in the
config) which is the most reliable option. Some backends do not have a practical way of choosing whether or not the device should be exclusive or not (ALSA,
for example) in which case it just acts as a hint. Unless you have special requirements you should try avoiding exclusive mode as it's intrusive to the user.
Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary.
When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by the config
and the format used internally by the backend. If you pass in 0 for the sample format, channel count, sample rate _and_ channel map, data transmission will run
on an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`,
`playback/capture.channels` and `sampleRate` members of the device object.
When compiling for UWP you must ensure you call this function on the main UI thread because the operating system may need to present the user with a message
asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information.
ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture.
If these fail it will try falling back to the "hw" device.
Example 1 - Simple Initialization
---------------------------------
This example shows how to initialize a simple playback device using a standard configuration. If you are just needing to do simple playback from the default
playback device this is usually all you need.
```c
ma_device_config config = ma_device_config_init(ma_device_type_playback);
config.playback.format = ma_format_f32;
config.playback.channels = 2;
config.sampleRate = 48000;
config.dataCallback = ma_data_callback;
config.pMyUserData = pMyUserData;
ma_device device;
ma_result result = ma_device_init(NULL, &config, &device);
if (result != MA_SUCCESS) {
// Error
}
```
Example 2 - Advanced Initialization
-----------------------------------
This example shows how you might do some more advanced initialization. In this hypothetical example we want to control the latency by setting the buffer size
and period count. We also want to allow the user to be able to choose which device to output from which means we need a context so we can perform device
enumeration.
```c
ma_context context;
ma_result result = ma_context_init(NULL, 0, NULL, &context);
if (result != MA_SUCCESS) {
// Error
}
ma_device_info* pPlaybackDeviceInfos;
ma_uint32 playbackDeviceCount;
result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
if (result != MA_SUCCESS) {
// Error
}
// ... choose a device from pPlaybackDeviceInfos ...
ma_device_config config = ma_device_config_init(ma_device_type_playback);
config.playback.pDeviceID = pMyChosenDeviceID; // <-- Get this from the `id` member of one of the `ma_device_info` objects returned by ma_context_get_devices().
config.playback.format = ma_format_f32;
config.playback.channels = 2;
config.sampleRate = 48000;
config.dataCallback = ma_data_callback;
config.pUserData = pMyUserData;
config.periodSizeInMilliseconds = 10;
config.periods = 3;
ma_device device;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_device_init()
ma_device_uninit()
ma_device_config_init()
ma_context_init()
*/
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);
/*
Uninitializes a device.
This will explicitly stop the device. You do not need to call `ma_device_stop()` beforehand, but it's harmless if you do.
Parameters
----------
pDevice (in)
A pointer to the device to stop.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. As soon as this API is called the device should be considered undefined.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
See Also
--------
ma_device_init()
ma_device_stop()
*/
MA_API void ma_device_uninit(ma_device* pDevice);
/*
Starts the device. For playback devices this begins playback. For capture devices it begins recording.
Use `ma_device_stop()` to stop the device.
Parameters
----------
pDevice (in)
A pointer to the device to start.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback.
Remarks
-------
For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid
audio data in the buffer, which needs to be done before the device begins playback.
This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety.
Do not call this in any callback.
See Also
--------
ma_device_stop()
*/
MA_API ma_result ma_device_start(ma_device* pDevice);
/*
Stops the device. For playback devices this stops playback. For capture devices it stops recording.
Use `ma_device_start()` to start the device again.
Parameters
----------
pDevice (in)
A pointer to the device to stop.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
Remarks
-------
This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some
backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size
that was specified at initialization time).
Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and
the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the
speakers or received from the microphone which can in turn result in de-syncs.
Do not call this in any callback.
This will be called implicitly by `ma_device_uninit()`.
See Also
--------
ma_device_start()
*/
MA_API ma_result ma_device_stop(ma_device* pDevice);
/*
Determines whether or not the device is started.
Parameters
----------
pDevice (in)
A pointer to the device whose start state is being retrieved.
Return Value
------------
True if the device is started, false otherwise.
Thread Safety
-------------
Safe. If another thread calls `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, there's a very small chance the return
value will be out of sync.
Callback Safety
---------------
Safe. This is implemented as a simple accessor.
See Also
--------
ma_device_start()
ma_device_stop()
*/
MA_API ma_bool32 ma_device_is_started(ma_device* pDevice);
/*
Sets the master volume factor for the device.
The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_gain_db()` to use decibel notation, where 0 is full volume and
values less than 0 decreases the volume.
Parameters
----------
pDevice (in)
A pointer to the device whose volume is being set.
volume (in)
The new volume factor. Must be within the range of [0, 1].
Return Value
------------
MA_SUCCESS if the volume was set successfully.
MA_INVALID_ARGS if pDevice is NULL.
MA_INVALID_ARGS if the volume factor is not within the range of [0, 1].
Thread Safety
-------------
Safe. This just sets a local member of the device object.
Callback Safety
---------------
Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
Remarks
-------
This applies the volume factor across all channels.
This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
See Also
--------
ma_device_get_master_volume()
ma_device_set_master_volume_gain_db()
ma_device_get_master_volume_gain_db()
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define MA_OPEN_MODE_READ 0x00000001
#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
ma_result result = ma_result_from_errno(errno);
if (result == MA_SUCCESS) {
result = MA_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
}
return result;
}
#endif
return MA_SUCCESS;
}
/*
_wfopen() isn't always available in all compilation environments.
* Windows only.
* MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
* MinGW-64 (both 32- and 64-bit) seems to support it.
* MinGW wraps it in !defined(__STRICT_ANSI__).
This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
*/
#if defined(_WIN32)
#if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
#define MA_HAS_WFOPEN
#endif
#endif
MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (ppFile != NULL) {
*ppFile = NULL; /* Safety. */
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return MA_INVALID_ARGS;
}
#if defined(MA_HAS_WFOPEN)
{
/* Use _wfopen() on Windows. */
#if defined(_MSC_VER) && _MSC_VER >= 1400
errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return ma_result_from_errno(err);
}
#else
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return ma_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
*/
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
/* Get the length first. */
MA_ZERO_OBJECT(&mbs);
lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
if (lenMB == (size_t)-1) {
return ma_result_from_errno(errno);
}
pFilePathMB = (char*)ma_malloc(lenMB + 1, pAllocationCallbacks);
if (pFilePathMB == NULL) {
return MA_OUT_OF_MEMORY;
}
pFilePathTemp = pFilePath;
MA_ZERO_OBJECT(&mbs);
wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
/* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
{
size_t i = 0;
for (;;) {
if (pOpenMode[i] == 0) {
pOpenModeMB[i] = '\0';
break;
}
pOpenModeMB[i] = (char)pOpenMode[i];
i += 1;
}
}
*ppFile = fopen(pFilePathMB, pOpenModeMB);
ma_free(pFilePathMB, pAllocationCallbacks);
}
if (*ppFile == NULL) {
return MA_ERROR;
}
#endif
return MA_SUCCESS;
}
static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes)
{
#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes);
#else
while (sizeInBytes > 0) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#endif
#if defined(MA_SUPPORT_AVX2)
static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a)
{
return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a));
}
#endif
#if defined(MA_SUPPORT_AVX512)
static MA_INLINE __m512 ma_mix_f32_fast__avx512(__m512 x, __m512 y, __m512 a)
{
return _mm512_add_ps(x, _mm512_mul_ps(_mm512_sub_ps(y, x), a));
}
#endif
#if defined(MA_SUPPORT_NEON)
static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a)
{
return vaddq_f32(x, vmulq_f32(vsubq_f32(y, x), a));
}
#endif
static MA_INLINE double ma_mix_f64(double x, double y, double a)
{
return x*(1-a) + y*a;
}
static MA_INLINE double ma_mix_f64_fast(double x, double y, double a)
{
return x + (y - x)*a;
}
static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi)
{
return lo + x*(hi-lo);
}
/*
Greatest common factor using Euclid's algorithm iteratively.
*/
static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b)
{
for (;;) {
if (b == 0) {
break;
} else {
ma_uint32 t = a;
a = b;
b = t % a;
}
}
return a;
}
/*
Random Number Generation
miniaudio uses the LCG random number generation algorithm. This is good enough for audio.
Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across
multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for
miniaudio's purposes.
*/
#ifndef MA_DEFAULT_LCG_SEED
#define MA_DEFAULT_LCG_SEED 4321
#endif
#define MA_LCG_M 2147483647
#define MA_LCG_A 48271
#define MA_LCG_C 0
static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */
static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed)
{
MA_ASSERT(pLCG != NULL);
pLCG->state = seed;
}
static MA_INLINE ma_int32 ma_lcg_rand_s32(ma_lcg* pLCG)
{
pLCG->state = (MA_LCG_A * pLCG->state + MA_LCG_C) % MA_LCG_M;
return pLCG->state;
}
static MA_INLINE ma_uint32 ma_lcg_rand_u32(ma_lcg* pLCG)
{
return (ma_uint32)ma_lcg_rand_s32(pLCG);
}
static MA_INLINE ma_int16 ma_lcg_rand_s16(ma_lcg* pLCG)
{
return (ma_int16)(ma_lcg_rand_s32(pLCG) & 0xFFFF);
}
static MA_INLINE double ma_lcg_rand_f64(ma_lcg* pLCG)
{
return ma_lcg_rand_s32(pLCG) / (double)0x7FFFFFFF;
}
static MA_INLINE float ma_lcg_rand_f32(ma_lcg* pLCG)
{
return (float)ma_lcg_rand_f64(pLCG);
}
static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg* pLCG, float lo, float hi)
{
return ma_scale_to_range_f32(ma_lcg_rand_f32(pLCG), lo, hi);
}
static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_int32 hi)
{
if (lo == hi) {
return lo;
}
return lo + ma_lcg_rand_u32(pLCG) / (0xFFFFFFFF / (hi - lo + 1) + 1);
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#ifdef __GNUC__
#ifdef __LP64__
#define C89ATOMIC_64BIT
#else
#define C89ATOMIC_32BIT
#endif
#endif
#endif
#if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
#include <stdint.h>
#if INTPTR_MAX == INT64_MAX
#define C89ATOMIC_64BIT
#else
#define C89ATOMIC_32BIT
#endif
#endif
#if defined(__x86_64__) || defined(_M_X64)
#define C89ATOMIC_X64
#elif defined(__i386) || defined(_M_IX86)
#define C89ATOMIC_X86
#elif defined(__arm__) || defined(_M_ARM)
#define C89ATOMIC_ARM
#endif
#ifdef _MSC_VER
#define C89ATOMIC_INLINE __forceinline
#elif defined(__GNUC__)
#if defined(__STRICT_ANSI__)
#define C89ATOMIC_INLINE __inline__ __attribute__((always_inline))
#else
#define C89ATOMIC_INLINE inline __attribute__((always_inline))
#endif
#else
#define C89ATOMIC_INLINE
#endif
#if defined(_MSC_VER)
#define c89atomic_memory_order_relaxed 0
#define c89atomic_memory_order_consume 1
#define c89atomic_memory_order_acquire 2
#define c89atomic_memory_order_release 3
#define c89atomic_memory_order_acq_rel 4
#define c89atomic_memory_order_seq_cst 5
#if _MSC_VER >= 1400
#include <intrin.h>
#define c89atomic_exchange_explicit_8( dst, src, order) (c89atomic_uint8 )_InterlockedExchange8 ((volatile char* )dst, (char )src)
#define c89atomic_exchange_explicit_16(dst, src, order) (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src)
#define c89atomic_exchange_explicit_32(dst, src, order) (c89atomic_uint32)_InterlockedExchange ((volatile long* )dst, (long )src)
#if defined(C89ATOMIC_64BIT)
#define c89atomic_exchange_explicit_64(dst, src, order) (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src)
#endif
#define c89atomic_fetch_add_explicit_8( dst, src, order) (c89atomic_uint8 )_InterlockedExchangeAdd8 ((volatile char* )dst, (char )src)
#define c89atomic_fetch_add_explicit_16(dst, src, order) (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src)
#define c89atomic_fetch_add_explicit_32(dst, src, order) (c89atomic_uint32)_InterlockedExchangeAdd ((volatile long* )dst, (long )src)
#if defined(C89ATOMIC_64BIT)
#define c89atomic_fetch_add_explicit_64(dst, src, order) (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src)
#endif
#define c89atomic_compare_and_swap_8( dst, expected, desired) (c89atomic_uint8 )_InterlockedCompareExchange8 ((volatile char* )dst, (char )desired, (char )expected)
#define c89atomic_compare_and_swap_16(dst, expected, desired) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short* )dst, (short )desired, (short )expected)
#define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange ((volatile long* )dst, (long )desired, (long )expected)
#define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile long long*)dst, (long long)desired, (long long)expected)
#if defined(C89ATOMIC_X64)
#define c89atomic_thread_fence(order) __faststorefence()
#else
static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order)
{
volatile c89atomic_uint32 barrier = 0;
(void)order;
c89atomic_fetch_add_explicit_32(&barrier, 0, order);
}
#endif
#else
#if defined(__i386) || defined(_M_IX86)
static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(int order)
{
volatile c89atomic_uint32 barrier;
(void)order;
__asm {
xchg barrier, eax
}
}
static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, int order)
{
(void)order;
__asm {
mov ecx, dst
mov al, src
lock xchg [ecx], al
}
}
static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, int order)
{
(void)order;
__asm {
mov ecx, dst
mov ax, src
lock xchg [ecx], ax
}
}
static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, int order)
{
(void)order;
__asm {
mov ecx, dst
mov eax, src
lock xchg [ecx], eax
}
}
static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, int order)
{
(void)order;
__asm {
mov ecx, dst
mov al, src
lock xadd [ecx], al
}
}
static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, int order)
{
(void)order;
__asm {
mov ecx, dst
mov ax, src
lock xadd [ecx], ax
}
}
static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, int order)
{
(void)order;
__asm {
mov ecx, dst
mov eax, src
lock xadd [ecx], eax
}
}
static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired)
{
__asm {
mov ecx, dst
mov al, expected
mov dl, desired
lock cmpxchg [ecx], dl
}
}
static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired)
{
__asm {
mov ecx, dst
mov ax, expected
mov dx, desired
lock cmpxchg [ecx], dx
}
}
static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired)
{
__asm {
mov ecx, dst
mov eax, expected
mov edx, desired
lock cmpxchg [ecx], edx
}
}
static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired)
{
__asm {
mov esi, dst
mov eax, dword ptr expected
mov edx, dword ptr expected + 4
mov ebx, dword ptr desired
mov ecx, dword ptr desired + 4
lock cmpxchg8b qword ptr [esi]
}
}
#else
error "Unsupported architecture."
#endif
#endif
#define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst)
#define c89atomic_signal_fence(order) c89atomic_thread_fence(order)
#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)
#define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order)
#define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order)
#if defined(C89ATOMIC_32BIT)
static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, int order)
{
volatile c89atomic_uint64 oldValue;
do {
oldValue = *dst;
} while (c89atomic_compare_and_swap_64(dst, oldValue, src) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, int order)
{
volatile c89atomic_uint64 oldValue;
volatile c89atomic_uint64 newValue;
do {
oldValue = *dst;
newValue = oldValue + src;
} while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
#endif
static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, int order)
{
volatile c89atomic_uint8 oldValue;
volatile c89atomic_uint8 newValue;
do {
oldValue = *dst;
newValue = (c89atomic_uint8)(oldValue - src);
} while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, int order)
{
volatile c89atomic_uint16 oldValue;
volatile c89atomic_uint16 newValue;
do {
oldValue = *dst;
newValue = (c89atomic_uint16)(oldValue - src);
} while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, int order)
{
volatile c89atomic_uint32 oldValue;
volatile c89atomic_uint32 newValue;
do {
oldValue = *dst;
newValue = oldValue - src;
} while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
do {
oldValue = *dst;
newValue = (c89atomic_uint8)(oldValue | src);
} while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, int order)
{
volatile c89atomic_uint16 oldValue;
volatile c89atomic_uint16 newValue;
do {
oldValue = *dst;
newValue = (c89atomic_uint16)(oldValue | src);
} while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, int order)
{
volatile c89atomic_uint32 oldValue;
volatile c89atomic_uint32 newValue;
do {
oldValue = *dst;
newValue = oldValue | src;
} while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, int order)
{
volatile c89atomic_uint64 oldValue;
volatile c89atomic_uint64 newValue;
do {
oldValue = *dst;
newValue = oldValue | src;
} while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
(void)order;
return oldValue;
}
#define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order)
#define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order)
#define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order)
#define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order)
#define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order)
#define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order)
#define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order)
#define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order)
#define c89atomic_flag_test_and_set_explicit(ptr, order) (c89atomic_flag)c89atomic_test_and_set_explicit_8(ptr, order)
#define c89atomic_flag_clear_explicit(ptr, order) c89atomic_clear_explicit_8(ptr, order)
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC__ >= 7)))
#define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
#define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE
#define c89atomic_memory_order_relaxed __ATOMIC_RELAXED
#define c89atomic_memory_order_consume __ATOMIC_CONSUME
#define c89atomic_memory_order_acquire __ATOMIC_ACQUIRE
#define c89atomic_memory_order_release __ATOMIC_RELEASE
#define c89atomic_memory_order_acq_rel __ATOMIC_ACQ_REL
#define c89atomic_memory_order_seq_cst __ATOMIC_SEQ_CST
#define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
#define c89atomic_thread_fence(order) __atomic_thread_fence(order)
#define c89atomic_signal_fence(order) __atomic_signal_fence(order)
#define c89atomic_is_lock_free_8(ptr) __atomic_is_lock_free(1, ptr)
#define c89atomic_is_lock_free_16(ptr) __atomic_is_lock_free(2, ptr)
#define c89atomic_is_lock_free_32(ptr) __atomic_is_lock_free(4, ptr)
#define c89atomic_is_lock_free_64(ptr) __atomic_is_lock_free(8, ptr)
#define c89atomic_flag_test_and_set_explicit(dst, order) (c89atomic_flag)__atomic_test_and_set(dst, order)
#define c89atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order)
#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)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* For robustness we're going to use a resampler object to calculate this since that already has a way of calculating this. */
ma_result result;
ma_uint64 frameCountOut;
ma_resampler_config config;
ma_resampler resampler;
if (sampleRateOut == sampleRateIn) {
return frameCountIn;
}
config = ma_resampler_config_init(ma_format_s16, 1, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear);
result = ma_resampler_init(&config, &resampler);
if (result != MA_SUCCESS) {
return 0;
}
frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn);
ma_resampler_uninit(&resampler);
return frameCountOut;
}
#ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE
#define MA_DATA_CONVERTER_STACK_BUFFER_SIZE 4096
#endif
#if defined(MA_WIN32)
static ma_result ma_result_from_GetLastError(DWORD error)
{
switch (error)
{
case ERROR_SUCCESS: return MA_SUCCESS;
case ERROR_PATH_NOT_FOUND: return MA_DOES_NOT_EXIST;
case ERROR_TOO_MANY_OPEN_FILES: return MA_TOO_MANY_OPEN_FILES;
case ERROR_NOT_ENOUGH_MEMORY: return MA_OUT_OF_MEMORY;
case ERROR_DISK_FULL: return MA_NO_SPACE;
case ERROR_HANDLE_EOF: return MA_END_OF_FILE;
case ERROR_NEGATIVE_SEEK: return MA_BAD_SEEK;
case ERROR_INVALID_PARAMETER: return MA_INVALID_ARGS;
case ERROR_ACCESS_DENIED: return MA_ACCESS_DENIED;
case ERROR_SEM_TIMEOUT: return MA_TIMEOUT;
case ERROR_FILE_NOT_FOUND: return MA_DOES_NOT_EXIST;
default: break;
}
return MA_ERROR;
}
#endif /* MA_WIN32 */
/*******************************************************************************
Threading
*******************************************************************************/
#ifndef MA_NO_THREADING
#ifdef MA_WIN32
#define MA_THREADCALL WINAPI
typedef unsigned long ma_thread_result;
#else
#define MA_THREADCALL
typedef void* ma_thread_result;
#endif
typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData);
static MA_INLINE ma_result ma_spinlock_lock_ex(ma_spinlock* pSpinlock, ma_bool32 yield)
{
if (pSpinlock == NULL) {
return MA_INVALID_ARGS;
}
for (;;) {
if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) {
break;
}
while (c89atomic_load_explicit_8(pSpinlock, c89atomic_memory_order_relaxed) == 1) {
if (yield) {
ma_yield();
}
}
}
return MA_SUCCESS;
}
MA_API ma_result ma_spinlock_lock(ma_spinlock* pSpinlock)
{
return ma_spinlock_lock_ex(pSpinlock, MA_TRUE);
}
MA_API ma_result ma_spinlock_lock_noyield(ma_spinlock* pSpinlock)
{
return ma_spinlock_lock_ex(pSpinlock, MA_FALSE);
}
MA_API ma_result ma_spinlock_unlock(ma_spinlock* pSpinlock)
{
if (pSpinlock == NULL) {
return MA_INVALID_ARGS;
}
c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release);
return MA_SUCCESS;
}
#ifdef MA_WIN32
static int ma_thread_priority_to_win32(ma_thread_priority priority)
{
switch (priority) {
case ma_thread_priority_idle: return THREAD_PRIORITY_IDLE;
case ma_thread_priority_lowest: return THREAD_PRIORITY_LOWEST;
case ma_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL;
case ma_thread_priority_normal: return THREAD_PRIORITY_NORMAL;
case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL;
case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST;
case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
default: return THREAD_PRIORITY_NORMAL;
}
}
static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
*pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL);
if (*pThread == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
SetThreadPriority((HANDLE)*pThread, ma_thread_priority_to_win32(priority));
return MA_SUCCESS;
}
static void ma_thread_wait__win32(ma_thread* pThread)
{
WaitForSingleObject((HANDLE)*pThread, INFINITE);
}
static ma_result ma_mutex_init__win32(ma_mutex* pMutex)
{
*pMutex = CreateEventW(NULL, FALSE, TRUE, NULL);
if (*pMutex == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
static void ma_mutex_uninit__win32(ma_mutex* pMutex)
{
CloseHandle((HANDLE)*pMutex);
}
static void ma_mutex_lock__win32(ma_mutex* pMutex)
{
WaitForSingleObject((HANDLE)*pMutex, INFINITE);
}
static void ma_mutex_unlock__win32(ma_mutex* pMutex)
{
SetEvent((HANDLE)*pMutex);
}
static ma_result ma_event_init__win32(ma_event* pEvent)
{
*pEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
if (*pEvent == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
static void ma_event_uninit__win32(ma_event* pEvent)
{
CloseHandle((HANDLE)*pEvent);
}
static ma_result ma_event_wait__win32(ma_event* pEvent)
{
DWORD result = WaitForSingleObject((HANDLE)*pEvent, INFINITE);
if (result == WAIT_OBJECT_0) {
return MA_SUCCESS;
}
if (result == WAIT_TIMEOUT) {
return MA_TIMEOUT;
}
return ma_result_from_GetLastError(GetLastError());
}
static ma_result ma_event_signal__win32(ma_event* pEvent)
{
BOOL result = SetEvent((HANDLE)*pEvent);
if (result == 0) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore)
{
*pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL);
if (*pSemaphore == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
static void ma_semaphore_uninit__win32(ma_semaphore* pSemaphore)
{
CloseHandle((HANDLE)*pSemaphore);
}
static ma_result ma_semaphore_wait__win32(ma_semaphore* pSemaphore)
{
DWORD result = WaitForSingleObject((HANDLE)*pSemaphore, INFINITE);
if (result == WAIT_OBJECT_0) {
return MA_SUCCESS;
}
if (result == WAIT_TIMEOUT) {
return MA_TIMEOUT;
}
return ma_result_from_GetLastError(GetLastError());
}
static ma_result ma_semaphore_release__win32(ma_semaphore* pSemaphore)
{
BOOL result = ReleaseSemaphore((HANDLE)*pSemaphore, 1, NULL);
if (result == 0) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
#endif
#ifdef MA_POSIX
static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
int result;
pthread_attr_t* pAttr = NULL;
#if !defined(__EMSCRIPTEN__)
/* Try setting the thread priority. It's not critical if anything fails here. */
pthread_attr_t attr;
if (pthread_attr_init(&attr) == 0) {
int scheduler = -1;
if (priority == ma_thread_priority_idle) {
#ifdef SCHED_IDLE
if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) {
scheduler = SCHED_IDLE;
}
#endif
} else if (priority == ma_thread_priority_realtime) {
#ifdef SCHED_FIFO
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) {
scheduler = SCHED_FIFO;
}
#endif
#ifdef MA_LINUX
} else {
scheduler = sched_getscheduler(0);
#endif
}
if (stackSize > 0) {
pthread_attr_setstacksize(&attr, stackSize);
}
if (scheduler != -1) {
int priorityMin = sched_get_priority_min(scheduler);
int priorityMax = sched_get_priority_max(scheduler);
int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */
struct sched_param sched;
if (pthread_attr_getschedparam(&attr, &sched) == 0) {
if (priority == ma_thread_priority_idle) {
sched.sched_priority = priorityMin;
} else if (priority == ma_thread_priority_realtime) {
sched.sched_priority = priorityMax;
} else {
sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */
if (sched.sched_priority < priorityMin) {
sched.sched_priority = priorityMin;
}
if (sched.sched_priority > priorityMax) {
sched.sched_priority = priorityMax;
}
}
if (pthread_attr_setschedparam(&attr, &sched) == 0) {
pAttr = &attr;
}
}
}
pthread_attr_destroy(&attr);
}
#else
/* It's the emscripten build. We'll have a few unused parameters. */
(void)priority;
(void)stackSize;
#endif
result = pthread_create(pThread, pAttr, entryProc, pData);
if (result != 0) {
return ma_result_from_errno(result);
}
return MA_SUCCESS;
}
static void ma_thread_wait__posix(ma_thread* pThread)
{
pthread_join(*pThread, NULL);
}
static ma_result ma_mutex_init__posix(ma_mutex* pMutex)
{
int result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL);
if (result != 0) {
return ma_result_from_errno(result);
}
return MA_SUCCESS;
}
static void ma_mutex_uninit__posix(ma_mutex* pMutex)
{
pthread_mutex_destroy((pthread_mutex_t*)pMutex);
}
static void ma_mutex_lock__posix(ma_mutex* pMutex)
{
pthread_mutex_lock((pthread_mutex_t*)pMutex);
}
static void ma_mutex_unlock__posix(ma_mutex* pMutex)
{
pthread_mutex_unlock((pthread_mutex_t*)pMutex);
}
static ma_result ma_event_init__posix(ma_event* pEvent)
{
int result;
result = pthread_mutex_init(&pEvent->lock, NULL);
if (result != 0) {
return ma_result_from_errno(result);
}
result = pthread_cond_init(&pEvent->cond, NULL);
if (result != 0) {
pthread_mutex_destroy(&pEvent->lock);
return ma_result_from_errno(result);
}
pEvent->value = 0;
return MA_SUCCESS;
}
static void ma_event_uninit__posix(ma_event* pEvent)
{
pthread_cond_destroy(&pEvent->cond);
pthread_mutex_destroy(&pEvent->lock);
}
static ma_result ma_event_wait__posix(ma_event* pEvent)
{
pthread_mutex_lock(&pEvent->lock);
{
while (pEvent->value == 0) {
pthread_cond_wait(&pEvent->cond, &pEvent->lock);
}
pEvent->value = 0; /* Auto-reset. */
}
pthread_mutex_unlock(&pEvent->lock);
return MA_SUCCESS;
}
static ma_result ma_event_signal__posix(ma_event* pEvent)
{
pthread_mutex_lock(&pEvent->lock);
{
pEvent->value = 1;
pthread_cond_signal(&pEvent->cond);
}
pthread_mutex_unlock(&pEvent->lock);
return MA_SUCCESS;
}
static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore)
{
int result;
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pSemaphore->value = initialValue;
result = pthread_mutex_init(&pSemaphore->lock, NULL);
if (result != 0) {
return ma_result_from_errno(result); /* Failed to create mutex. */
}
result = pthread_cond_init(&pSemaphore->cond, NULL);
if (result != 0) {
pthread_mutex_destroy(&pSemaphore->lock);
return ma_result_from_errno(result); /* Failed to create condition variable. */
}
return MA_SUCCESS;
}
static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return;
}
pthread_cond_destroy(&pSemaphore->cond);
pthread_mutex_destroy(&pSemaphore->lock);
}
static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pthread_mutex_lock(&pSemaphore->lock);
{
/* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */
while (pSemaphore->value == 0) {
pthread_cond_wait(&pSemaphore->cond, &pSemaphore->lock);
}
pSemaphore->value -= 1;
}
pthread_mutex_unlock(&pSemaphore->lock);
return MA_SUCCESS;
}
static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
return MA_INVALID_ARGS;
}
pthread_mutex_lock(&pSemaphore->lock);
{
pSemaphore->value += 1;
pthread_cond_signal(&pSemaphore->cond);
}
pthread_mutex_unlock(&pSemaphore->lock);
return MA_SUCCESS;
}
#endif
static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
{
if (pThread == NULL || entryProc == NULL) {
return MA_FALSE;
}
#ifdef MA_WIN32
return ma_thread_create__win32(pThread, priority, stackSize, entryProc, pData);
#endif
#ifdef MA_POSIX
return ma_thread_create__posix(pThread, priority, stackSize, entryProc, pData);
#endif
}
static void ma_thread_wait(ma_thread* pThread)
{
if (pThread == NULL) {
return;
}
#ifdef MA_WIN32
ma_thread_wait__win32(pThread);
#endif
#ifdef MA_POSIX
ma_thread_wait__posix(pThread);
#endif
}
MA_API ma_result ma_mutex_init(ma_mutex* pMutex)
{
if (pMutex == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */
return MA_INVALID_ARGS;
}
#ifdef MA_WIN32
return ma_mutex_init__win32(pMutex);
#endif
#ifdef MA_POSIX
return ma_mutex_init__posix(pMutex);
#endif
}
MA_API void ma_mutex_uninit(ma_mutex* pMutex)
{
if (pMutex == NULL) {
return;
}
#ifdef MA_WIN32
ma_mutex_uninit__win32(pMutex);
#endif
#ifdef MA_POSIX
ma_mutex_uninit__posix(pMutex);
#endif
}
MA_API void ma_mutex_lock(ma_mutex* pMutex)
{
if (pMutex == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */
return;
}
#ifdef MA_WIN32
ma_mutex_lock__win32(pMutex);
#endif
#ifdef MA_POSIX
ma_mutex_lock__posix(pMutex);
#endif
}
MA_API void ma_mutex_unlock(ma_mutex* pMutex)
{
if (pMutex == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert to the caller is aware of this bug. */
return;
}
#ifdef MA_WIN32
ma_mutex_unlock__win32(pMutex);
#endif
#ifdef MA_POSIX
ma_mutex_unlock__posix(pMutex);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */
return MA_INVALID_ARGS;
}
#ifdef MA_WIN32
return ma_semaphore_init__win32(initialValue, pSemaphore);
#endif
#ifdef MA_POSIX
return ma_semaphore_init__posix(initialValue, pSemaphore);
#endif
}
MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */
return;
}
#ifdef MA_WIN32
ma_semaphore_uninit__win32(pSemaphore);
#endif
#ifdef MA_POSIX
ma_semaphore_uninit__posix(pSemaphore);
#endif
}
MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */
return MA_INVALID_ARGS;
}
#ifdef MA_WIN32
return ma_semaphore_wait__win32(pSemaphore);
#endif
#ifdef MA_POSIX
return ma_semaphore_wait__posix(pSemaphore);
#endif
}
MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore)
{
if (pSemaphore == NULL) {
MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */
return MA_INVALID_ARGS;
}
#ifdef MA_WIN32
return ma_semaphore_release__win32(pSemaphore);
#endif
#ifdef MA_POSIX
return ma_semaphore_release__posix(pSemaphore);
#endif
}
#else
/* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
#ifndef MA_NO_DEVICE_IO
#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
#endif
#endif /* MA_NO_THREADING */
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
DEVICE I/O
==========
*************************************************************************************************************************************************************
************************************************************************************************************************************************************/
#ifndef MA_NO_DEVICE_IO
#ifdef MA_WIN32
#include <objbase.h>
#include <mmreg.h>
#include <mmsystem.h>
#endif
#if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
#include <mach/mach_time.h> /* For mach_absolute_time() */
#endif
#ifdef MA_POSIX
#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
#endif
/*
Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply
disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
*/
/*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/
/* Disable run-time linking on certain backends. */
#ifndef MA_NO_RUNTIME_LINKING
#if defined(MA_ANDROID) || defined(MA_EMSCRIPTEN)
#define MA_NO_RUNTIME_LINKING
#endif
#endif
/*
Check if we have the necessary development packages for each backend at the top so we can use this to determine whether or not
certain unused functions and variables can be excluded from the build to avoid warnings.
*/
#ifdef MA_ENABLE_WASAPI
#define MA_HAS_WASAPI /* Every compiler should support WASAPI */
#endif
#ifdef MA_ENABLE_DSOUND
#define MA_HAS_DSOUND /* Every compiler should support DirectSound. */
#endif
#ifdef MA_ENABLE_WINMM
#define MA_HAS_WINMM /* Every compiler I'm aware of supports WinMM. */
#endif
#ifdef MA_ENABLE_ALSA
#define MA_HAS_ALSA
#ifdef MA_NO_RUNTIME_LINKING
#ifdef __has_include
#if !__has_include(<alsa/asoundlib.h>)
#undef MA_HAS_ALSA
#endif
#endif
#endif
#endif
#ifdef MA_ENABLE_PULSEAUDIO
#define MA_HAS_PULSEAUDIO
#ifdef MA_NO_RUNTIME_LINKING
#ifdef __has_include
#if !__has_include(<pulse/pulseaudio.h>)
#undef MA_HAS_PULSEAUDIO
#endif
#endif
#endif
#endif
#ifdef MA_ENABLE_JACK
#define MA_HAS_JACK
#ifdef MA_NO_RUNTIME_LINKING
#ifdef __has_include
#if !__has_include(<jack/jack.h>)
#undef MA_HAS_JACK
#endif
#endif
#endif
#endif
#ifdef MA_ENABLE_COREAUDIO
#define MA_HAS_COREAUDIO
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
case MA_AUDCLNT_E_RESOURCES_INVALIDATED: return MA_INVALID_DATA;
case MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED: return MA_INVALID_OPERATION;
case MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED: return MA_INVALID_OPERATION;
case MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED: return MA_INVALID_OPERATION;
case MA_AUDCLNT_E_HEADTRACKING_ENABLED: return MA_INVALID_OPERATION;
case MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED: return MA_INVALID_OPERATION;
case MA_AUDCLNT_S_BUFFER_EMPTY: return MA_NO_SPACE;
case MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED: return MA_ALREADY_EXISTS;
case MA_AUDCLNT_S_POSITION_STALLED: return MA_ERROR;
/* DirectSound */
/*case MA_DS_OK: return MA_SUCCESS;*/ /* S_OK */
case MA_DS_NO_VIRTUALIZATION: return MA_SUCCESS;
case MA_DSERR_ALLOCATED: return MA_ALREADY_IN_USE;
case MA_DSERR_CONTROLUNAVAIL: return MA_INVALID_OPERATION;
/*case MA_DSERR_INVALIDPARAM: return MA_INVALID_ARGS;*/ /* E_INVALIDARG */
case MA_DSERR_INVALIDCALL: return MA_INVALID_OPERATION;
/*case MA_DSERR_GENERIC: return MA_ERROR;*/ /* E_FAIL */
case MA_DSERR_PRIOLEVELNEEDED: return MA_INVALID_OPERATION;
/*case MA_DSERR_OUTOFMEMORY: return MA_OUT_OF_MEMORY;*/ /* E_OUTOFMEMORY */
case MA_DSERR_BADFORMAT: return MA_FORMAT_NOT_SUPPORTED;
/*case MA_DSERR_UNSUPPORTED: return MA_NOT_IMPLEMENTED;*/ /* E_NOTIMPL */
case MA_DSERR_NODRIVER: return MA_FAILED_TO_INIT_BACKEND;
case MA_DSERR_ALREADYINITIALIZED: return MA_DEVICE_ALREADY_INITIALIZED;
case MA_DSERR_NOAGGREGATION: return MA_ERROR;
case MA_DSERR_BUFFERLOST: return MA_UNAVAILABLE;
case MA_DSERR_OTHERAPPHASPRIO: return MA_ACCESS_DENIED;
case MA_DSERR_UNINITIALIZED: return MA_DEVICE_NOT_INITIALIZED;
/*case MA_DSERR_NOINTERFACE: return MA_API_NOT_FOUND;*/ /* E_NOINTERFACE */
/*case MA_DSERR_ACCESSDENIED: return MA_ACCESS_DENIED;*/ /* E_ACCESSDENIED */
case MA_DSERR_BUFFERTOOSMALL: return MA_NO_SPACE;
case MA_DSERR_DS8_REQUIRED: return MA_INVALID_OPERATION;
case MA_DSERR_SENDLOOP: return MA_DEADLOCK;
case MA_DSERR_BADSENDBUFFERGUID: return MA_INVALID_ARGS;
case MA_DSERR_OBJECTNOTFOUND: return MA_NO_DEVICE;
case MA_DSERR_FXUNAVAILABLE: return MA_UNAVAILABLE;
default: return MA_ERROR;
}
}
typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit);
typedef void (WINAPI * MA_PFN_CoUninitialize)(void);
typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
typedef void (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv);
typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar);
typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax);
typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void);
typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void);
/* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */
typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey);
typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
#endif
#define MA_STATE_UNINITIALIZED 0
#define MA_STATE_STOPPED 1 /* The device's default state after initialization. */
#define MA_STATE_STARTED 2 /* The worker thread is in it's main loop waiting for the driver to request or deliver audio data. */
#define MA_STATE_STARTING 3 /* Transitioning from a stopped state to started. */
#define MA_STATE_STOPPING 4 /* Transitioning from a started state to stopped. */
#define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device"
#define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device"
MA_API const char* ma_log_level_to_string(ma_uint32 logLevel)
{
switch (logLevel)
{
case MA_LOG_LEVEL_VERBOSE: return "";
case MA_LOG_LEVEL_INFO: return "INFO";
case MA_LOG_LEVEL_WARNING: return "WARNING";
case MA_LOG_LEVEL_ERROR: return "ERROR";
default: return "ERROR";
}
}
/* Posts a log message. */
static void ma_post_log_message(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
{
if (pContext == NULL) {
if (pDevice != NULL) {
pContext = pDevice->pContext;
}
}
/* All logs must be output when debug output is enabled. */
#if defined(MA_DEBUG_OUTPUT)
printf("%s: %s\n", ma_log_level_to_string(logLevel), message);
#endif
if (pContext == NULL) {
return;
}
#if defined(MA_LOG_LEVEL)
if (logLevel <= MA_LOG_LEVEL) {
ma_log_proc onLog;
onLog = pContext->logCallback;
if (onLog) {
onLog(pContext, pDevice, logLevel, message);
}
}
#endif
}
/*
We need to emulate _vscprintf() for the VC6 build. This can be more efficient, but since it's only VC6, and it's just a
logging function, I'm happy to keep this simple. In the VC6 build we can implement this in terms of _vsnprintf().
*/
#if defined(_MSC_VER) && _MSC_VER < 1900
int ma_vscprintf(const char* format, va_list args)
{
#if _MSC_VER > 1200
return _vscprintf(format, args);
#else
int result;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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) {
return MA_NO_DEVICE;
}
data.deviceType = deviceType;
data.pDeviceID = pDeviceID;
data.pName = pName;
data.nameBufferSize = nameBufferSize;
data.foundDevice = MA_FALSE;
result = ma_context_enumerate_devices(pContext, ma_context__try_get_device_name_by_id__enum_callback, &data);
if (result != MA_SUCCESS) {
return result;
}
if (!data.foundDevice) {
return MA_NO_DEVICE;
} else {
return MA_SUCCESS;
}
}
MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */
{
ma_uint32 i;
for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) {
if (g_maFormatPriorities[i] == format) {
return i;
}
}
/* Getting here means the format could not be found or is equal to ma_format_unknown. */
return (ma_uint32)-1;
}
static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType);
/*******************************************************************************
Null Backend
*******************************************************************************/
#ifdef MA_HAS_NULL
#define MA_DEVICE_OP_NONE__NULL 0
#define MA_DEVICE_OP_START__NULL 1
#define MA_DEVICE_OP_SUSPEND__NULL 2
#define MA_DEVICE_OP_KILL__NULL 3
static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
for (;;) { /* Keep the thread alive until the device is uninitialized. */
/* Wait for an operation to be requested. */
ma_event_wait(&pDevice->null_device.operationEvent);
/* At this point an event should have been triggered. */
/* Starting the device needs to put the thread into a loop. */
if (pDevice->null_device.operation == MA_DEVICE_OP_START__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
/* Reset the timer just in case. */
ma_timer_init(&pDevice->null_device.timer);
/* Keep looping until an operation has been requested. */
while (pDevice->null_device.operation != MA_DEVICE_OP_NONE__NULL && pDevice->null_device.operation != MA_DEVICE_OP_START__NULL) {
ma_sleep(10); /* Don't hog the CPU. */
}
/* Getting here means a suspend or kill operation has been requested. */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue;
}
/* Suspending the device means we need to stop the timer and just continue the loop. */
if (pDevice->null_device.operation == MA_DEVICE_OP_SUSPEND__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
/* We need to add the current run time to the prior run time, then reset the timer. */
pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
ma_timer_init(&pDevice->null_device.timer);
/* We're done. */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue;
}
/* Killing the device means we need to get out of this loop so that this thread can terminate. */
if (pDevice->null_device.operation == MA_DEVICE_OP_KILL__NULL) {
c89atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, MA_SUCCESS);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
break;
}
/* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
if (pDevice->null_device.operation == MA_DEVICE_OP_NONE__NULL) {
MA_ASSERT(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */
c89atomic_exchange_32((c89atomic_uint32*)&pDevice->null_device.operationResult, (c89atomic_uint32)MA_INVALID_OPERATION);
ma_event_signal(&pDevice->null_device.operationCompletionEvent);
continue; /* Continue the loop. Don't terminate. */
}
}
return (ma_thread_result)0;
}
static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
{
c89atomic_exchange_32(&pDevice->null_device.operation, operation);
if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
return MA_ERROR;
}
if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) {
return MA_ERROR;
}
return pDevice->null_device.operationResult;
}
static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice)
{
ma_uint32 internalSampleRate;
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
internalSampleRate = pDevice->capture.internalSampleRate;
} else {
internalSampleRate = pDevice->playback.internalSampleRate;
}
return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate);
}
static ma_bool32 ma_context_is_device_id_equal__null(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pID0 != NULL);
MA_ASSERT(pID1 != NULL);
(void)pContext;
return pID0->nullbackend == pID1->nullbackend;
}
static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
ma_bool32 cbResult = MA_TRUE;
MA_ASSERT(pContext != NULL);
MA_ASSERT(callback != NULL);
/* Playback. */
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1);
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
}
/* Capture. */
if (cbResult) {
ma_device_info deviceInfo;
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1);
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
}
return MA_SUCCESS;
}
static ma_result ma_context_get_device_info__null(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
{
ma_uint32 iFormat;
MA_ASSERT(pContext != NULL);
if (pDeviceID != NULL && pDeviceID->nullbackend != 0) {
return MA_NO_DEVICE; /* Don't know the device. */
}
/* Name / Description */
if (deviceType == ma_device_type_playback) {
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1);
}
/* Support everything on the null backend. */
pDeviceInfo->formatCount = ma_format_count - 1; /* Minus one because we don't want to include ma_format_unknown. */
for (iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) {
pDeviceInfo->formats[iFormat] = (ma_format)(iFormat + 1); /* +1 to skip over ma_format_unknown. */
}
pDeviceInfo->minChannels = 1;
pDeviceInfo->maxChannels = MA_MAX_CHANNELS;
pDeviceInfo->minSampleRate = MA_SAMPLE_RATE_8000;
pDeviceInfo->maxSampleRate = MA_SAMPLE_RATE_384000;
(void)pContext;
(void)shareMode;
return MA_SUCCESS;
}
static void ma_device_uninit__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/* Keep it clean and wait for the device thread to finish before returning. */
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL);
/* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
ma_event_uninit(&pDevice->null_device.operationEvent);
}
static ma_result ma_device_init__null(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
{
ma_result result;
ma_uint32 periodSizeInFrames;
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->null_device);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
periodSizeInFrames = pConfig->periodSizeInFrames;
if (periodSizeInFrames == 0) {
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pConfig->sampleRate);
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "NULL Capture Device", (size_t)-1);
pDevice->capture.internalFormat = pConfig->capture.format;
pDevice->capture.internalChannels = pConfig->capture.channels;
ma_channel_map_copy(pDevice->capture.internalChannelMap, pConfig->capture.channelMap, ma_min(pConfig->capture.channels, MA_MAX_CHANNELS));
pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->capture.internalPeriods = pConfig->periods;
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1);
pDevice->playback.internalFormat = pConfig->playback.format;
pDevice->playback.internalChannels = pConfig->playback.channels;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pConfig->playback.channelMap, ma_min(pConfig->playback.channels, MA_MAX_CHANNELS));
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->playback.internalPeriods = pConfig->periods;
}
/*
In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the
first period is "written" to it, and then stopped in ma_device_stop__null().
*/
result = ma_event_init(&pDevice->null_device.operationEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_event_init(&pDevice->null_device.operationCompletionEvent);
if (result != MA_SUCCESS) {
return result;
}
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, 0, ma_device_thread__null, pDevice);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static ma_result ma_device_start__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL);
c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE);
return MA_SUCCESS;
}
static ma_result ma_device_stop__null(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL);
c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE);
return MA_SUCCESS;
}
static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{
ma_result result = MA_SUCCESS;
ma_uint32 totalPCMFramesProcessed;
ma_bool32 wasStartedOnEntry;
if (pFramesWritten != NULL) {
*pFramesWritten = 0;
}
wasStartedOnEntry = pDevice->null_device.isStarted;
/* Keep going until everything has been read. */
totalPCMFramesProcessed = 0;
while (totalPCMFramesProcessed < frameCount) {
ma_uint64 targetFrame;
/* If there are any frames remaining in the current period, consume those first. */
if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) {
ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingPlayback;
if (framesToProcess > framesRemaining) {
framesToProcess = framesRemaining;
}
/* We don't actually do anything with pPCMFrames, so just mark it as unused to prevent a warning. */
(void)pPCMFrames;
pDevice->null_device.currentPeriodFramesRemainingPlayback -= framesToProcess;
totalPCMFramesProcessed += framesToProcess;
}
/* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
} ma_IAudioRenderClientVtbl;
struct ma_IAudioRenderClient
{
ma_IAudioRenderClientVtbl* lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
static MA_INLINE ULONG ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioRenderClient_Release(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData) { return pThis->lpVtbl->GetBuffer(pThis, numFramesRequested, ppData); }
static MA_INLINE HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesWritten, dwFlags); }
/* IAudioCaptureClient */
typedef struct
{
/* IUnknown */
HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject);
ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioCaptureClient* pThis);
ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioCaptureClient* pThis);
/* IAudioRenderClient */
HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition);
HRESULT (STDMETHODCALLTYPE * ReleaseBuffer) (ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead);
HRESULT (STDMETHODCALLTYPE * GetNextPacketSize)(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket);
} ma_IAudioCaptureClientVtbl;
struct ma_IAudioCaptureClient
{
ma_IAudioCaptureClientVtbl* lpVtbl;
};
static MA_INLINE HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
static MA_INLINE ULONG ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->AddRef(pThis); }
static MA_INLINE ULONG ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->Release(pThis); }
static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition) { return pThis->lpVtbl->GetBuffer(pThis, ppData, ...
static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); }
static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket) { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); }
#ifndef MA_WIN32_DESKTOP
#include <mmdeviceapi.h>
typedef struct ma_completion_handler_uwp ma_completion_handler_uwp;
typedef struct
{
/* IUnknown */
HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject);
ULONG (STDMETHODCALLTYPE * AddRef) (ma_completion_handler_uwp* pThis);
ULONG (STDMETHODCALLTYPE * Release) (ma_completion_handler_uwp* pThis);
/* IActivateAudioInterfaceCompletionHandler */
HRESULT (STDMETHODCALLTYPE * ActivateCompleted)(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation);
} ma_completion_handler_uwp_vtbl;
struct ma_completion_handler_uwp
{
ma_completion_handler_uwp_vtbl* lpVtbl;
ma_uint32 counter;
HANDLE hEvent;
};
static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject)
{
/*
We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To
"implement" this, we just make sure we return pThis when the IAgileObject is requested.
*/
if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IActivateAudioInterfaceCompletionHandler) && !ma_is_guid_equal(riid, &MA_IID_IAgileObject)) {
*ppObject = NULL;
return E_NOINTERFACE;
}
/* Getting here means the IID is IUnknown or IMMNotificationClient. */
*ppObject = (void*)pThis;
((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
return S_OK;
}
static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis)
{
return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1;
}
static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp* pThis)
{
ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1;
if (newRefCount == 0) {
return 0; /* We don't free anything here because we never allocate the object on the heap. */
}
return (ULONG)newRefCount;
}
static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation)
{
(void)pActivateOperation;
SetEvent(pThis->hEvent);
return S_OK;
}
static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance = {
ma_completion_handler_uwp_QueryInterface,
ma_completion_handler_uwp_AddRef,
ma_completion_handler_uwp_Release,
ma_completion_handler_uwp_ActivateCompleted
};
static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHandler)
{
MA_ASSERT(pHandler != NULL);
MA_ZERO_OBJECT(pHandler);
pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance;
pHandler->counter = 1;
pHandler->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
if (pHandler->hEvent == NULL) {
return ma_result_from_GetLastError(GetLastError());
}
return MA_SUCCESS;
}
static void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler)
{
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
data.sampleRateIn = pConfig->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap));
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
data.shareMode = pConfig->playback.shareMode;
/* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
if (pConfig->deviceType == ma_device_type_duplex) {
data.periodSizeInFramesIn = pDevice->capture.internalPeriodSizeInFrames;
data.periodsIn = pDevice->capture.internalPeriods;
data.registerStopEvent = MA_FALSE;
} else {
data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
data.periodsIn = pConfig->periods;
data.registerStopEvent = MA_TRUE;
}
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data, (void*)pDevice);
if (result != MA_SUCCESS) {
if (pConfig->deviceType == ma_device_type_duplex) {
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
if (pDevice->coreaudio.pAudioBufferList) {
ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
}
}
return result;
}
pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL);
#if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
#endif
pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
pDevice->playback.internalFormat = data.formatOut;
pDevice->playback.internalChannels = data.channelsOut;
pDevice->playback.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->playback.internalPeriods = data.periodsOut;
#if defined(MA_APPLE_DESKTOP)
/*
If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
switch the device in the background.
*/
if (pConfig->playback.pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pConfig->capture.pDeviceID != NULL)) {
ma_device__track__coreaudio(pDevice);
}
#endif
}
pDevice->coreaudio.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
pDevice->coreaudio.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
pDevice->coreaudio.originalPeriods = pConfig->periods;
/*
When stopping the device, a callback is called on another thread. We need to wait for this callback
before returning from ma_device_stop(). This event is used for this.
*/
ma_event_init(&pDevice->coreaudio.stopEvent);
/* Need a ring buffer for duplex mode. */
if (pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 rbSizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods);
ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->coreaudio.duplexRB);
if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result);
}
/* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
{
ma_uint32 bufferSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
void* pBufferData;
ma_pcm_rb_acquire_write(&pDevice->coreaudio.duplexRB, &bufferSizeInFrames, &pBufferData);
{
MA_ZERO_MEMORY(pBufferData, bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
}
ma_pcm_rb_commit_write(&pDevice->coreaudio.duplexRB, bufferSizeInFrames, pBufferData);
}
}
/*
We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
differently on non-Desktop Apple platforms.
*/
#if defined(MA_APPLE_MOBILE)
pDevice->coreaudio.pRouteChangeHandler = (__bridge_retained void*)[[ma_router_change_handler alloc] init:pDevice];
#endif
return MA_SUCCESS;
}
static ma_result ma_device_start__coreaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
if (status != noErr) {
return ma_result_from_OSStatus(status);
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
if (status != noErr) {
if (pDevice->type == ma_device_type_duplex) {
((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
}
return ma_result_from_OSStatus(status);
}
}
return MA_SUCCESS;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
pDevice->capture.internalPeriods = (ma_uint32)(ossFragment >> 16);
pDevice->capture.internalPeriodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
if (pDevice->capture.internalFormat == ma_format_unknown) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
}
} else {
pDevice->oss.fdPlayback = fd;
pDevice->playback.internalFormat = ma_format_from_oss(ossFormat);
pDevice->playback.internalChannels = ossChannels;
pDevice->playback.internalSampleRate = ossSampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
pDevice->playback.internalPeriods = (ma_uint32)(ossFragment >> 16);
pDevice->playback.internalPeriodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
if (pDevice->playback.internalFormat == ma_format_unknown) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
}
}
return MA_SUCCESS;
}
static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->oss);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_capture, pDevice);
if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
}
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_playback, pDevice);
if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
}
}
return MA_SUCCESS;
}
static ma_result ma_device_stop__oss(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/*
We want to use SNDCTL_DSP_HALT. From the documentation:
In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread
that actually reads/writes the audio device. It must not be called by some master thread to kill the
audio thread. The audio thread will not stop or get any kind of notification that the device was
stopped by the master thread. The device gets stopped but the next read or write call will silently
restart the device.
This is actually safe in our case, because this function is only ever called from within our worker
thread anyway. Just keep this in mind, though...
*/
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
int result = ioctl(pDevice->oss.fdCapture, SNDCTL_DSP_HALT, 0);
if (result == -1) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
int result = ioctl(pDevice->oss.fdPlayback, SNDCTL_DSP_HALT, 0);
if (result == -1) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
}
}
return MA_SUCCESS;
}
static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{
int resultOSS;
if (pFramesWritten != NULL) {
*pFramesWritten = 0;
}
resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
if (resultOSS < 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno));
}
if (pFramesWritten != NULL) {
*pFramesWritten = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
}
return MA_SUCCESS;
}
static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
{
int resultOSS;
if (pFramesRead != NULL) {
*pFramesRead = 0;
}
resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
if (resultOSS < 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno));
}
if (pFramesRead != NULL) {
*pFramesRead = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
}
return MA_SUCCESS;
}
static ma_result ma_device_main_loop__oss(ma_device* pDevice)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define MA_AAUDIO_CALLBACK_RESULT_CONTINUE 0
#define MA_AAUDIO_CALLBACK_RESULT_STOP 1
/* Objects. */
typedef struct ma_AAudioStreamBuilder_t* ma_AAudioStreamBuilder;
typedef struct ma_AAudioStream_t* ma_AAudioStream;
typedef ma_aaudio_data_callback_result_t (* ma_AAudioStream_dataCallback) (ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t numFrames);
typedef void (* ma_AAudioStream_errorCallback)(ma_AAudioStream *pStream, void *pUserData, ma_aaudio_result_t error);
typedef ma_aaudio_result_t (* MA_PFN_AAudio_createStreamBuilder) (ma_AAudioStreamBuilder** ppBuilder);
typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_delete) (ma_AAudioStreamBuilder* pBuilder);
typedef void (* MA_PFN_AAudioStreamBuilder_setDeviceId) (ma_AAudioStreamBuilder* pBuilder, int32_t deviceId);
typedef void (* MA_PFN_AAudioStreamBuilder_setDirection) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_direction_t direction);
typedef void (* MA_PFN_AAudioStreamBuilder_setSharingMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_sharing_mode_t sharingMode);
typedef void (* MA_PFN_AAudioStreamBuilder_setFormat) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_format_t format);
typedef void (* MA_PFN_AAudioStreamBuilder_setChannelCount) (ma_AAudioStreamBuilder* pBuilder, int32_t channelCount);
typedef void (* MA_PFN_AAudioStreamBuilder_setSampleRate) (ma_AAudioStreamBuilder* pBuilder, int32_t sampleRate);
typedef void (* MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
typedef void (* MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
typedef void (* MA_PFN_AAudioStreamBuilder_setDataCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_dataCallback callback, void* pUserData);
typedef void (* MA_PFN_AAudioStreamBuilder_setErrorCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_errorCallback callback, void* pUserData);
typedef void (* MA_PFN_AAudioStreamBuilder_setPerformanceMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_performance_mode_t mode);
typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_openStream) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream);
typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_close) (ma_AAudioStream* pStream);
typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState) (ma_AAudioStream* pStream);
typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_waitForStateChange) (ma_AAudioStream* pStream, ma_aaudio_stream_state_t inputState, ma_aaudio_stream_state_t* pNextState, int64_t timeoutInNanoseconds);
typedef ma_aaudio_format_t (* MA_PFN_AAudioStream_getFormat) (ma_AAudioStream* pStream);
typedef int32_t (* MA_PFN_AAudioStream_getChannelCount) (ma_AAudioStream* pStream);
typedef int32_t (* MA_PFN_AAudioStream_getSampleRate) (ma_AAudioStream* pStream);
typedef int32_t (* MA_PFN_AAudioStream_getBufferCapacityInFrames) (ma_AAudioStream* pStream);
typedef int32_t (* MA_PFN_AAudioStream_getFramesPerDataCallback) (ma_AAudioStream* pStream);
typedef int32_t (* MA_PFN_AAudioStream_getFramesPerBurst) (ma_AAudioStream* pStream);
typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStart) (ma_AAudioStream* pStream);
typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStop) (ma_AAudioStream* pStream);
static ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA)
{
switch (resultAA)
{
case MA_AAUDIO_OK: return MA_SUCCESS;
default: break;
}
return MA_ERROR;
}
static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUserData, ma_aaudio_result_t error)
{
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
(void)error;
#if defined(MA_DEBUG_OUTPUT)
printf("[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
#endif
/*
From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need
to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely.
*/
if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
#if defined(MA_DEBUG_OUTPUT)
printf("[AAudio] Device Disconnected.\n");
#endif
}
}
static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
{
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_capture(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB);
} else {
ma_device__send_frames_to_client(pDevice, frameCount, pAudioData); /* Send directly to the client. */
}
(void)pStream;
return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
}
static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
{
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_playback(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB);
} else {
ma_device__read_frames_from_client(pDevice, frameCount, pAudioData); /* Read directly from the client. */
}
(void)pStream;
return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
}
static ma_result ma_open_stream__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, const ma_device_config* pConfig, const ma_device* pDevice, ma_AAudioStream** ppStream)
{
ma_AAudioStreamBuilder* pBuilder;
ma_aaudio_result_t resultAA;
MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */
*ppStream = NULL;
resultAA = ((MA_PFN_AAudio_createStreamBuilder)pContext->aaudio.AAudio_createStreamBuilder)(&pBuilder);
if (resultAA != MA_AAUDIO_OK) {
return ma_result_from_aaudio(resultAA);
}
if (pDeviceID != NULL) {
((MA_PFN_AAudioStreamBuilder_setDeviceId)pContext->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder, pDeviceID->aaudio);
}
((MA_PFN_AAudioStreamBuilder_setDirection)pContext->aaudio.AAudioStreamBuilder_setDirection)(pBuilder, (deviceType == ma_device_type_playback) ? MA_AAUDIO_DIRECTION_OUTPUT : MA_AAUDIO_DIRECTION_INPUT);
((MA_PFN_AAudioStreamBuilder_setSharingMode)pContext->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder, (shareMode == ma_share_mode_shared) ? MA_AAUDIO_SHARING_MODE_SHARED : MA_AAUDIO_SHARING_MODE_EXCLUSIVE);
if (pConfig != NULL) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
}
if (pDevice->usingDefaultSampleRate) {
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
pDevice->sampleRate = pDevice->capture.internalSampleRate;
} else {
pDevice->sampleRate = pDevice->playback.internalSampleRate;
}
}
/* Data converters. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
/* Converting from internal device format to client format. */
ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
converterConfig.formatIn = pDevice->capture.internalFormat;
converterConfig.channelsIn = pDevice->capture.internalChannels;
converterConfig.sampleRateIn = pDevice->capture.internalSampleRate;
ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, ma_min(pDevice->capture.internalChannels, MA_MAX_CHANNELS));
converterConfig.formatOut = pDevice->capture.format;
converterConfig.channelsOut = pDevice->capture.channels;
converterConfig.sampleRateOut = pDevice->sampleRate;
ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS));
converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality;
result = ma_data_converter_init(&converterConfig, &pDevice->capture.converter);
if (result != MA_SUCCESS) {
return result;
}
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
/* Converting from client format to device format. */
ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
converterConfig.formatIn = pDevice->playback.format;
converterConfig.channelsIn = pDevice->playback.channels;
converterConfig.sampleRateIn = pDevice->sampleRate;
ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, ma_min(pDevice->playback.channels, MA_MAX_CHANNELS));
converterConfig.formatOut = pDevice->playback.internalFormat;
converterConfig.channelsOut = pDevice->playback.internalChannels;
converterConfig.sampleRateOut = pDevice->playback.internalSampleRate;
ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS));
converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality;
result = ma_data_converter_init(&converterConfig, &pDevice->playback.converter);
if (result != MA_SUCCESS) {
return result;
}
}
return MA_SUCCESS;
}
static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
{
ma_device* pDevice = (ma_device*)pData;
MA_ASSERT(pDevice != NULL);
#ifdef MA_WIN32
ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE);
#endif
/*
When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from
ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately
after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker
thread to signal an event to know when the worker thread is ready for action.
*/
ma_device__set_state(pDevice, MA_STATE_STOPPED);
ma_event_signal(&pDevice->stopEvent);
for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
ma_stop_proc onStop;
/* We wait on an event to know when something has requested that the device be started and the main loop entered. */
ma_event_wait(&pDevice->wakeupEvent);
/* Default result code. */
pDevice->workResult = MA_SUCCESS;
/* If the reason for the wake up is that we are terminating, just break from the loop. */
if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
break;
}
/*
Getting to this point means the device is wanting to get started. The function that has requested that the device
be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event
in both the success and error case. It's important that the state of the device is set _before_ signaling the event.
*/
MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STARTING);
/* Make sure the state is set appropriately. */
ma_device__set_state(pDevice, MA_STATE_STARTED);
ma_event_signal(&pDevice->startEvent);
if (pDevice->pContext->onDeviceMainLoop != NULL) {
pDevice->pContext->onDeviceMainLoop(pDevice);
} else {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "No main loop implementation.", MA_API_NOT_FOUND);
}
/*
Getting here means we have broken from the main loop which happens the application has requested that device be stopped. Note that this
may have actually already happened above if the device was lost and miniaudio has attempted to re-initialize the device. In this case we
don't want to be doing this a second time.
*/
if (ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED) {
if (pDevice->pContext->onDeviceStop) {
pDevice->pContext->onDeviceStop(pDevice);
}
}
/* After the device has stopped, make sure an event is posted. */
onStop = pDevice->onStop;
if (onStop) {
onStop(pDevice);
}
/*
A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. Note that
it's possible that the device has been uninitialized which means we need to _not_ change the status to stopped. We cannot go from an
uninitialized state to stopped state.
*/
if (ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED) {
ma_device__set_state(pDevice, MA_STATE_STOPPED);
ma_event_signal(&pDevice->stopEvent);
}
}
/* Make sure we aren't continuously waiting on a stop event. */
ma_event_signal(&pDevice->stopEvent); /* <-- Is this still needed? */
#ifdef MA_WIN32
ma_CoUninitialize(pDevice->pContext);
#endif
return (ma_thread_result)0;
}
/* Helper for determining whether or not the given device is initialized. */
static ma_bool32 ma_device__is_initialized(ma_device* pDevice)
{
if (pDevice == NULL) {
return MA_FALSE;
}
return ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED;
}
#ifdef MA_WIN32
static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext)
{
ma_CoUninitialize(pContext);
ma_dlclose(pContext, pContext->win32.hUser32DLL);
ma_dlclose(pContext, pContext->win32.hOle32DLL);
ma_dlclose(pContext, pContext->win32.hAdvapi32DLL);
return MA_SUCCESS;
}
static ma_result ma_context_init_backend_apis__win32(ma_context* pContext)
{
#ifdef MA_WIN32_DESKTOP
/* Ole32.dll */
pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll");
if (pContext->win32.hOle32DLL == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx");
pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize");
pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance");
pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree");
pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear");
pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2");
/* User32.dll */
pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll");
if (pContext->win32.hUser32DLL == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow");
pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow");
/* Advapi32.dll */
pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll");
if (pContext->win32.hAdvapi32DLL == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA");
pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey");
pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA");
#endif
ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE);
return MA_SUCCESS;
}
#else
static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext)
{
#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
ma_dlclose(pContext, pContext->posix.pthreadSO);
#else
(void)pContext;
#endif
return MA_SUCCESS;
}
static ma_result ma_context_init_backend_apis__nix(ma_context* pContext)
{
/* pthread */
#if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
const char* libpthreadFileNames[] = {
"libpthread.so",
"libpthread.so.0",
"libpthread.dylib"
};
size_t i;
for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]);
if (pContext->posix.pthreadSO != NULL) {
break;
}
}
if (pContext->posix.pthreadSO == NULL) {
return MA_FAILED_TO_INIT_BACKEND;
}
pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create");
pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join");
pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init");
pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy");
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);
}
MA_ASSERT(pBackendsToIterate != NULL);
for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) {
ma_backend backend = pBackendsToIterate[iBackend];
result = MA_NO_BACKEND;
switch (backend) {
#ifdef MA_HAS_WASAPI
case ma_backend_wasapi:
{
result = ma_context_init__wasapi(&config, pContext);
} break;
#endif
#ifdef MA_HAS_DSOUND
case ma_backend_dsound:
{
result = ma_context_init__dsound(&config, pContext);
} break;
#endif
#ifdef MA_HAS_WINMM
case ma_backend_winmm:
{
result = ma_context_init__winmm(&config, pContext);
} break;
#endif
#ifdef MA_HAS_ALSA
case ma_backend_alsa:
{
result = ma_context_init__alsa(&config, pContext);
} break;
#endif
#ifdef MA_HAS_PULSEAUDIO
case ma_backend_pulseaudio:
{
result = ma_context_init__pulse(&config, pContext);
} break;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
result = ma_context_init__jack(&config, pContext);
} break;
#endif
#ifdef MA_HAS_COREAUDIO
case ma_backend_coreaudio:
{
result = ma_context_init__coreaudio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_SNDIO
case ma_backend_sndio:
{
result = ma_context_init__sndio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_AUDIO4
case ma_backend_audio4:
{
result = ma_context_init__audio4(&config, pContext);
} break;
#endif
#ifdef MA_HAS_OSS
case ma_backend_oss:
{
result = ma_context_init__oss(&config, pContext);
} break;
#endif
#ifdef MA_HAS_AAUDIO
case ma_backend_aaudio:
{
result = ma_context_init__aaudio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_OPENSL
case ma_backend_opensl:
{
result = ma_context_init__opensl(&config, pContext);
} break;
#endif
#ifdef MA_HAS_WEBAUDIO
case ma_backend_webaudio:
{
result = ma_context_init__webaudio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_NULL
case ma_backend_null:
{
result = ma_context_init__null(&config, pContext);
} break;
#endif
default: break;
}
/* If this iteration was successful, return. */
if (result == MA_SUCCESS) {
result = ma_mutex_init(&pContext->deviceEnumLock);
if (result != MA_SUCCESS) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.", result);
}
result = ma_mutex_init(&pContext->deviceInfoLock);
if (result != MA_SUCCESS) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.", result);
}
#ifdef MA_DEBUG_OUTPUT
printf("[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE");
printf("[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO");
printf("[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO");
printf("[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO");
printf("[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO");
#endif
pContext->backend = backend;
return result;
}
}
/* If we get here it means an error occurred. */
MA_ZERO_OBJECT(pContext); /* Safety. */
return MA_NO_BACKEND;
}
MA_API ma_result ma_context_uninit(ma_context* pContext)
{
if (pContext == NULL) {
return MA_INVALID_ARGS;
}
pContext->onUninit(pContext);
ma_mutex_uninit(&pContext->deviceEnumLock);
ma_mutex_uninit(&pContext->deviceInfoLock);
ma__free_from_callbacks(pContext->pDeviceInfos, &pContext->allocationCallbacks);
ma_context_uninit_backend_apis(pContext);
return MA_SUCCESS;
}
MA_API size_t ma_context_sizeof()
{
return sizeof(ma_context);
}
MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
ma_result result;
if (pContext == NULL || pContext->onEnumDevices == NULL || callback == NULL) {
return MA_INVALID_ARGS;
}
ma_mutex_lock(&pContext->deviceEnumLock);
{
result = pContext->onEnumDevices(pContext, callback, pUserData);
}
ma_mutex_unlock(&pContext->deviceEnumLock);
return result;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
/* Default periods. */
if (config.periods == 0) {
config.periods = MA_DEFAULT_PERIODS;
pDevice->usingDefaultPeriods = MA_TRUE;
}
/*
Must have at least 3 periods for full-duplex mode. The idea is that the playback and capture positions hang out in the middle period, with the surrounding
periods acting as a buffer in case the capture and playback devices get's slightly out of sync.
*/
if (config.deviceType == ma_device_type_duplex && config.periods < 3) {
config.periods = 3;
}
/* Default buffer size. */
if (config.periodSizeInMilliseconds == 0 && config.periodSizeInFrames == 0) {
config.periodSizeInMilliseconds = (config.performanceProfile == ma_performance_profile_low_latency) ? MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
pDevice->usingDefaultBufferSize = MA_TRUE;
}
MA_ASSERT(config.capture.channels <= MA_MAX_CHANNELS);
MA_ASSERT(config.playback.channels <= MA_MAX_CHANNELS);
pDevice->type = config.deviceType;
pDevice->sampleRate = config.sampleRate;
pDevice->resampling.algorithm = config.resampling.algorithm;
pDevice->resampling.linear.lpfOrder = config.resampling.linear.lpfOrder;
pDevice->resampling.speex.quality = config.resampling.speex.quality;
pDevice->capture.shareMode = config.capture.shareMode;
pDevice->capture.format = config.capture.format;
pDevice->capture.channels = config.capture.channels;
ma_channel_map_copy(pDevice->capture.channelMap, config.capture.channelMap, config.capture.channels);
pDevice->playback.shareMode = config.playback.shareMode;
pDevice->playback.format = config.playback.format;
pDevice->playback.channels = config.playback.channels;
ma_channel_map_copy(pDevice->playback.channelMap, config.playback.channelMap, config.playback.channels);
/* The internal format, channel count and sample rate can be modified by the backend. */
pDevice->capture.internalFormat = pDevice->capture.format;
pDevice->capture.internalChannels = pDevice->capture.channels;
pDevice->capture.internalSampleRate = pDevice->sampleRate;
ma_channel_map_copy(pDevice->capture.internalChannelMap, pDevice->capture.channelMap, pDevice->capture.channels);
pDevice->playback.internalFormat = pDevice->playback.format;
pDevice->playback.internalChannels = pDevice->playback.channels;
pDevice->playback.internalSampleRate = pDevice->sampleRate;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pDevice->playback.channelMap, pDevice->playback.channels);
result = ma_mutex_init(&pDevice->lock);
if (result != MA_SUCCESS) {
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result);
}
/*
When the device is started, the worker thread is the one that does the actual startup of the backend device. We
use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
Each of these semaphores is released internally by the worker thread when the work is completed. The start
semaphore is also used to wake up the worker thread.
*/
result = ma_event_init(&pDevice->wakeupEvent);
if (result != MA_SUCCESS) {
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result);
}
result = ma_event_init(&pDevice->startEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result);
}
result = ma_event_init(&pDevice->stopEvent);
if (result != MA_SUCCESS) {
ma_event_uninit(&pDevice->startEvent);
ma_event_uninit(&pDevice->wakeupEvent);
ma_mutex_uninit(&pDevice->lock);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result);
}
result = pContext->onDeviceInit(pContext, &config, pDevice);
if (result != MA_SUCCESS) {
return result;
}
ma_device__post_init_setup(pDevice, pConfig->deviceType);
/* If the backend did not fill out a name for the device, try a generic method. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->capture.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_capture, config.capture.pDeviceID, pDevice->capture.name, sizeof(pDevice->capture.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), (config.capture.pDeviceID == NULL) ? MA_DEFAULT_CAPTURE_DEVICE_NAME : "Capture Device", (size_t)-1);
}
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
if (pDevice->playback.name[0] == '\0') {
if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_playback, config.playback.pDeviceID, pDevice->playback.name, sizeof(pDevice->playback.name)) != MA_SUCCESS) {
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), (config.playback.pDeviceID == NULL) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1);
}
}
}
/* Some backends don't require the worker thread. */
if (!ma_context_is_backend_asynchronous(pContext)) {
/* The worker thread. */
result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice);
if (result != MA_SUCCESS) {
ma_device_uninit(pDevice);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result);
}
/* 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;
}
if (pContextConfig != NULL) {
result = ma_allocation_callbacks_init_copy(&allocationCallbacks, &pContextConfig->allocationCallbacks);
if (result != MA_SUCCESS) {
return result;
}
} 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) {
return MA_INVALID_ARGS;
}
return ma_device_set_master_volume(pDevice, ma_gain_db_to_factor(gainDB));
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define DRFLAC_BAD_ADDRESS -24
#define DRFLAC_BAD_SEEK -25
#define DRFLAC_BAD_PIPE -26
#define DRFLAC_DEADLOCK -27
#define DRFLAC_TOO_MANY_LINKS -28
#define DRFLAC_NOT_IMPLEMENTED -29
#define DRFLAC_NO_MESSAGE -30
#define DRFLAC_BAD_MESSAGE -31
#define DRFLAC_NO_DATA_AVAILABLE -32
#define DRFLAC_INVALID_DATA -33
#define DRFLAC_TIMEOUT -34
#define DRFLAC_NO_NETWORK -35
#define DRFLAC_NOT_UNIQUE -36
#define DRFLAC_NOT_SOCKET -37
#define DRFLAC_NO_ADDRESS -38
#define DRFLAC_BAD_PROTOCOL -39
#define DRFLAC_PROTOCOL_UNAVAILABLE -40
#define DRFLAC_PROTOCOL_NOT_SUPPORTED -41
#define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED -42
#define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED -43
#define DRFLAC_SOCKET_NOT_SUPPORTED -44
#define DRFLAC_CONNECTION_RESET -45
#define DRFLAC_ALREADY_CONNECTED -46
#define DRFLAC_NOT_CONNECTED -47
#define DRFLAC_CONNECTION_REFUSED -48
#define DRFLAC_NO_HOST -49
#define DRFLAC_IN_PROGRESS -50
#define DRFLAC_CANCELLED -51
#define DRFLAC_MEMORY_ALREADY_MAPPED -52
#define DRFLAC_AT_END -53
#define DRFLAC_CRC_MISMATCH -128
#define DRFLAC_SUBFRAME_CONSTANT 0
#define DRFLAC_SUBFRAME_VERBATIM 1
#define DRFLAC_SUBFRAME_FIXED 8
#define DRFLAC_SUBFRAME_LPC 32
#define DRFLAC_SUBFRAME_RESERVED 255
#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0
#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0
#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8
#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9
#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10
#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision)
{
if (pMajor) {
*pMajor = DRFLAC_VERSION_MAJOR;
}
if (pMinor) {
*pMinor = DRFLAC_VERSION_MINOR;
}
if (pRevision) {
*pRevision = DRFLAC_VERSION_REVISION;
}
}
DRFLAC_API const char* drflac_version_string(void)
{
return DRFLAC_VERSION_STRING;
}
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#else
#define DRFLAC_NO_THREAD_SANITIZE
#endif
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
#endif
#ifndef DRFLAC_NO_CPUID
static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE;
static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
{
static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE;
if (!isCPUCapsInitialized) {
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
int info[4] = {0};
drflac__cpuid(info, 0x80000001);
drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
#endif
drflac__gIsSSE2Supported = drflac_has_sse2();
drflac__gIsSSE41Supported = drflac_has_sse41();
isCPUCapsInitialized = DRFLAC_TRUE;
}
}
#else
static drflac_bool32 drflac__gIsNEONSupported = DRFLAC_FALSE;
static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void)
{
#if defined(DRFLAC_SUPPORT_NEON)
#if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON)
#if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
return DRFLAC_TRUE;
#else
return DRFLAC_FALSE;
#endif
#else
return DRFLAC_FALSE;
#endif
#else
return DRFLAC_FALSE;
#endif
}
DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
{
drflac__gIsNEONSupported = drflac__has_neon();
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
drflac__gIsLZCNTSupported = DRFLAC_TRUE;
#endif
}
#endif
static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void)
{
#if defined(DRFLAC_X86) || defined(DRFLAC_X64)
return DRFLAC_TRUE;
#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
return DRFLAC_TRUE;
#else
int n = 1;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
Miscellaneous Changes
---------------------
The following miscellaneous changes have also been made.
- The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the record, this is one of the nicest
audio APIs out there, just behind the BSD audio APIs).
- The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL.
- The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio was not explicitly
supported. These are no longer needed and have therefore been removed.
- Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an exclusive mode device, or an
error. The rationale for this change is to give the client more control over how to handle cases when the desired shared mode is unavailable.
- A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb" operates on PCM frames.
- The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but removes the attribution
requirement. The rationale for this is to support countries that don't recognize public domain.
*/
/*
REVISION HISTORY
================
v0.10.21 - 2020-10-30
- Add ma_is_backend_enabled() and ma_get_enabled_backends() for retrieving enabled backends at run-time.
- WASAPI: Fix a copy and paste bug relating to loopback mode.
- Core Audio: Fix a bug when using multiple contexts.
- Core Audio: Fix a compilation warning.
- Core Audio: Improvements to sample rate selection.
- Core Audio: Improvements to format/channels/rate selection when requesting defaults.
- Core Audio: Add notes regarding the Apple notarization process.
- Fix some bugs due to null pointer dereferences.
v0.10.20 - 2020-10-06
- Fix build errors with UWP.
- Minor documentation updates.
v0.10.19 - 2020-09-22
- WASAPI: Return an error when exclusive mode is requested, but the native format is not supported by miniaudio.
- Fix a bug where ma_decoder_seek_to_pcm_frames() never returns MA_SUCCESS even though it was successful.
- Store the sample rate in the `ma_lpf` and `ma_hpf` structures.
v0.10.18 - 2020-08-30
- Fix build errors with VC6.
- Fix a bug in channel converter for s32 format.
- Change channel converter configs to use the default channel map instead of a blank channel map when no channel map is specified when initializing the
config. This fixes an issue where the optimized mono expansion path would never get used.
- Use a more appropriate default format for FLAC decoders. This will now use ma_format_s16 when the FLAC is encoded as 16-bit.
- Update FLAC decoder.
- Update links to point to the new repository location (https://github.com/mackron/miniaudio).
v0.10.17 - 2020-08-28
- Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set.
- Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed.
- Fix compilation error on Android.
- Core Audio: Fix a bug with full-duplex mode.
- Add ma_decoder_get_cursor_in_pcm_frames().
- Update WAV codec.
v0.10.16 - 2020-08-14
- WASAPI: Fix a potential crash due to using an uninitialized variable.
- OpenSL: Enable runtime linking.
- OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time.
- iOS: Improvements to device enumeration.
- Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL.
- Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work.
- Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled.
- Fix some compilation warnings when no decoders are enabled.
- Add ma_audio_buffer_get_available_frames().
- Add ma_decoder_get_available_frames().
- Add sample rate to ma_data_source_get_data_format().
- Change volume APIs to take 64-bit frame counts.
- Updates to documentation.
v0.10.15 - 2020-07-15
- Fix a bug when converting bit-masked channel maps to miniaudio channel maps. This affects the WASAPI and OpenSL backends.
v0.10.14 - 2020-07-14
- Fix compilation errors on Android.
- Fix compilation errors with -march=armv6.
- Updates to the documentation.
v0.10.13 - 2020-07-11
- Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS.
- Fix compilation error on Emscripten.
- Silence some unused function warnings.
- Increase the default buffer size on the Web Audio backend. This fixes glitching issues on some browsers.
- Bring FLAC decoder up-to-date with dr_flac.
- Bring MP3 decoder up-to-date with dr_mp3.
v0.10.12 - 2020-07-04
- Fix compilation errors on the iOS build.
v0.10.11 - 2020-06-28
- Fix some bugs with device tracking on Core Audio.
- Updates to documentation.
v0.10.10 - 2020-06-26
- Add include guard for the implementation section.
- Mark ma_device_sink_info_callback() as static.
- Fix compilation errors with MA_NO_DECODING and MA_NO_ENCODING.
- Fix compilation errors with MA_NO_DEVICE_IO
v0.10.9 - 2020-06-24
- Amalgamation of dr_wav, dr_flac and dr_mp3. With this change, including the header section of these libraries before the implementation of miniaudio is no
longer required. Decoding of WAV, FLAC and MP3 should be supported seamlessly without any additional libraries. Decoders can be excluded from the build
with the following options:
- MA_NO_WAV
- MA_NO_FLAC
- MA_NO_MP3
If you get errors about multiple definitions you need to either enable the options above, move the implementation of dr_wav, dr_flac and/or dr_mp3 to before
the implementation of miniaudio, or update dr_wav, dr_flac and/or dr_mp3.
- Changes to the internal atomics library. This has been replaced with c89atomic.h which is embedded within this file.
- Fix a bug when a decoding backend reports configurations outside the limits of miniaudio's decoder abstraction.
- Fix the UWP build.
- Fix the Core Audio build.
- Fix the -std=c89 build on GCC.
v0.10.8 - 2020-06-22
- Remove dependency on ma_context from mutexes.
- Change ma_data_source_read_pcm_frames() to return a result code and output the frames read as an output parameter.
- Change ma_data_source_seek_pcm_frames() to return a result code and output the frames seeked as an output parameter.
- Change ma_audio_buffer_unmap() to return MA_AT_END when the end has been reached. This should be considered successful.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- Fix a bug on iOS where the device name is not set correctly.
v0.8.11 - 2018-11-21
- iOS bug fixes.
- Minor tweaks to PulseAudio.
v0.8.10 - 2018-10-21
- Core Audio: Fix a hang when uninitializing a device.
- Fix a bug where an incorrect value is returned from mal_device_stop().
v0.8.9 - 2018-09-28
- Fix a bug with the SDL backend where device initialization fails.
v0.8.8 - 2018-09-14
- Fix Linux build with the ALSA backend.
- Minor documentation fix.
v0.8.7 - 2018-09-12
- Fix a bug with UWP detection.
v0.8.6 - 2018-08-26
- Automatically switch the internal device when the default device is unplugged. Note that this is still in the
early stages and not all backends handle this the same way. As of this version, this will not detect a default
device switch when changed from the operating system's audio preferences (unless the backend itself handles
this automatically). This is not supported in exclusive mode.
- WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the
user switches the default device via the operating system's audio preferences, miniaudio will automatically switch
the internal device to the new default. This is not supported in exclusive mode.
- WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer.
- WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer.
- Add support for compiling the UWP build as C.
- mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this
when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0.
v0.8.5 - 2018-08-12
- Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in
frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0
then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used.
- Add support for the audio(4) backend to OpenBSD.
- Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the
Raspberry Pi experience.
- Fix a bug where an incorrect number of samples is returned from sinc resampling.
- Add support for setting the value to be passed to internal calls to CoInitializeEx().
- WASAPI and WinMM: Stop the device when it is unplugged.
v0.8.4 - 2018-08-06
- Add sndio backend for OpenBSD.
- Add audio(4) backend for NetBSD.
- Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD.
- Formats are now native-endian (were previously little-endian).
- Mark some APIs as deprecated:
- mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate().
- mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate().
- Fix a bug when capturing using the WASAPI backend.
- Fix some aliasing issues with resampling, specifically when increasing the sample rate.
- Fix warnings.
v0.8.3 - 2018-07-15
- Fix a crackling bug when resampling in capture mode.
- Core Audio: Fix a bug where capture does not work.
- ALSA: Fix a bug where the worker thread can get stuck in an infinite loop.
- PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable.
- JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable.
v0.8.2 - 2018-07-07
- Fix a bug on macOS with Core Audio where the internal callback is not called.
v0.8.1 - 2018-07-06
- Fix compilation errors and warnings.
v0.8 - 2018-07-05
- Changed MAL_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old
way is still supported for now, but you should update as it may be removed in the future.
- API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with
mal_context_get_devices(). An additional low-level device enumration API has been introduced called
mal_context_enumerate_devices() which uses a callback to report devices.
- API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add
mal_get_bytes_per_frame().
- API CHANGE: Replace mal_device_config.preferExclusiveMode with mal_device_config.shareMode.
- This new config can be set to mal_share_mode_shared (default) or mal_share_mode_exclusive.
- API CHANGE: Remove excludeNullDevice from mal_context_config.alsa.
- API CHANGE: Rename MAL_MAX_SAMPLE_SIZE_IN_BYTES to MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES.
- API CHANGE: Change the default channel mapping to the standard Microsoft mapping.
- API CHANGE: Remove backend-specific result codes.
- API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.)
- Add support for Core Audio (Apple).
- Add support for PulseAudio.
- This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly
installed by default on many of the popular distros and offer's more seamless integration on
platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which
is extremely common), it's better to just use PulseAudio directly rather than going through the
"pulse" ALSA plugin (which is what the "default" ALSA device is likely set to).
- Add support for JACK.
- Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no
longer required to build miniaudio.
- Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some
distributions of MinGW.
- Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some
distributions of MinGW.
- Add support for dithering to format conversion.
- Add support for configuring the priority of the worker thread.
- Add a sine wave generator.
- Improve efficiency of sample rate conversion.
- Introduce the notion of standard channel maps. Use mal_get_standard_channel_map().
- Introduce the notion of default device configurations. A default config uses the same configuration
as the backend's internal device, and as such results in a pass-through data transmission pipeline.
- Add support for passing in NULL for the device config in mal_device_init(), which uses a default
config. This requires manually calling mal_device_set_send/recv_callback().
- Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.)
- Make mal_device_init_ex() more robust.
- Make some APIs more const-correct.
- Fix errors with SDL detection on Apple platforms.
- Fix errors with OpenAL detection.
- Fix some memory leaks.
- Fix a bug with opening decoders from memory.
- Early work on SSE2, AVX2 and NEON optimizations.
- Miscellaneous bug fixes.
- Documentation updates.
v0.7 - 2018-02-25
- API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts.
- Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files.
- Allow opening of devices without a context.
- In this case the context is created and managed internally by the device.
- Change the default channel mapping to the same as that used by FLAC.
- Fix build errors with macOS.
v0.6c - 2018-02-12
- Fix build errors with BSD/OSS.
v0.6b - 2018-02-03
- Fix some warnings when compiling with Visual C++.
v0.6a - 2018-01-26
- Fix errors with channel mixing when increasing the channel count.
- Improvements to the build system for the OpenAL backend.
- Documentation fixes.
v0.6 - 2017-12-08
- API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll
need to update.
- API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively.
- API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent.
- Add support for SDL and Emscripten.
- Simplify the build system further for when development packages for various backends are not installed.
With this change, when the compiler supports __has_include, backends without the relevant development
packages installed will be ignored. This fixes the build for old versions of MinGW.
- Fixes to the Android build.
- Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of
audio data to a different format.
- Improvements to f32 -> u8/s16/s24/s32 conversion routines.
- Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend.
- Fixes and improvements for Raspberry Pi.
- Warning fixes.
v0.5 - 2017-11-11
- API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for
configuring the context. The works in the same kind of way as the device config. The rationale for this
change is to give applications better control over context-level properties, add support for backend-
specific configurations, and support extensibility without breaking the API.
- API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for
anything anymore.
- ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications
can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config
variable.
- ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If
this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now
honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above)
which is by design.
- ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable.
- ALSA: Fix a bug with channel mapping which causes an assertion to fail.
- Fix errors with enumeration when pInfo is set to NULL.
- OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill.
v0.4 - 2017-11-05
- API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to
mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic
messages at the context level. Previously this was only available at the device level.
- API CHANGE: The device config passed to mal_device_init() is now const.
- Added support for OSS which enables support on BSD platforms.
- Added support for WinMM (waveOut/waveIn).
- Added support for UWP (Universal Windows Platform) applications. Currently C++ only.
- Added support for exclusive mode for selected backends. Currently supported on WASAPI.
- POSIX builds no longer require explicit linking to libpthread (-lpthread).
- ALSA: Explicit linking to libasound (-lasound) is no longer required.
- ALSA: Latency improvements.
- ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config.
- ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the
alsa.preferPlugHW config.
- WASAPI is now the highest priority backend on Windows platforms.
- Fixed an error with sample rate conversion which was causing crackling when capturing.
- Improved error handling.
- Improved compiler support.
- Miscellaneous bug fixes.
v0.3 - 2017-06-19
- API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for
enumerating and creating devices. Now, applications must first create a context, and then use that to
enumerate and create devices. The reason for this change is to ensure device enumeration and creation is
tied to the same backend. In addition, some backends are better suited to this design.
- API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard
to test and maintain, and just generally unreliable.
- Added helper APIs for initializing mal_device_config objects.
- Null Backend: Fixed a crash when recording.
- Fixed build for UWP.
- Added support for f32 formats to the OpenSL|ES backend.
- Added initial implementation of the WASAPI backend.
- Added initial implementation of the OpenAL backend.
- Added support for low quality linear sample rate conversion.
- Added early support for basic channel mapping.
v0.2 - 2016-10-28
- API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this
change is to ensure the logging callback has access to the user data during initialization.
- API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale:
1) The number of parameters is just getting too much.
2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a
chance there will be support added for backend-specific properties.
- Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the
added maintenance cost.
- DirectSound: Increased the default buffer size for capture devices.
- Added initial implementation of the OpenSL|ES backend.
v0.1 - 2016-10-21
- Initial versioned release.
*/
/*
This software is available as a choice of the following licenses. Choose
whichever you prefer.
===============================================================================
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
===============================================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to