view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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
--------
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second.
3.5. Formats
------------
Throughout miniaudio you will see references to different sample formats:
+---------------+----------------------------------------+---------------------------+
| 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] |
+---------------+----------------------------------------+---------------------------+
All formats are native-endian.
4. Decoding
===========
The `ma_decoder` API is used for reading audio files. The following formats are supported:
+---------+------------------+----------+
| Format | Decoding Backend | Built-In |
+---------+------------------+----------+
| WAV | dr_wav | Yes |
| MP3 | dr_mp3 | Yes |
| FLAC | dr_flac | Yes |
| Vorbis | stb_vorbis | No |
+---------+------------------+----------+
Vorbis is supported via stb_vorbis which can be enabled by including the header section before the implementation of miniaudio, like the following:
```c
#define STB_VORBIS_HEADER_ONLY
#include "extras/stb_vorbis.c" // Enables Vorbis decoding.
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
// The stb_vorbis implementation must come after the implementation of miniaudio.
#undef STB_VORBIS_HEADER_ONLY
#include "extras/stb_vorbis.c"
```
A copy of stb_vorbis is included in the "extras" folder in the miniaudio repository (https://github.com/mackron/miniaudio).
Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the built-in decoders by specifying one or more of the
following options before the miniaudio implementation:
```c
#define MA_NO_WAV
#define MA_NO_MP3
#define MA_NO_FLAC
```
Disabling built-in decoding libraries is useful if you use these libraries independantly of the `ma_decoder` API.
A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with `ma_decoder_init_memory()`, or from data delivered via callbacks
with `ma_decoder_init()`. Here is an example for loading a decoder from a file:
```c
ma_decoder decoder;
ma_result result = ma_decoder_init_file("MySong.mp3", NULL, &decoder);
if (result != MA_SUCCESS) {
return false; // An error occurred.
}
...
ma_decoder_uninit(&decoder);
```
When initializing a decoder, you can optionally pass in a pointer to a ma_decoder_config object (the NULL argument in the example above) which allows you to
configure the output format, channel count, sample rate and channel map:
```c
ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000);
```
When passing in NULL for decoder config in `ma_decoder_init*()`, the output format will be the same as that defined by the decoding backend.
Data is read from the decoder as PCM frames. This will return the number of PCM frames actually read. If the return value is less than the requested number of
PCM frames it means you've reached the end:
```c
ma_uint64 framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead);
if (framesRead < framesToRead) {
// Reached the end.
}
```
You can also seek to a specific frame like so:
```c
ma_result result = ma_decoder_seek_to_pcm_frame(pDecoder, targetFrame);
if (result != MA_SUCCESS) {
return false; // An error occurred.
}
```
If you want to loop back to the start, you can simply seek back to the first PCM frame:
```c
ma_decoder_seek_to_pcm_frame(pDecoder, 0);
```
When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type
is already known. In this case you can use the `_wav`, `_mp3`, etc. varients of the aforementioned initialization APIs:
```c
ma_decoder_init_wav()
ma_decoder_init_mp3()
ma_decoder_init_memory_wav()
ma_decoder_init_memory_mp3()
ma_decoder_init_file_wav()
ma_decoder_init_file_mp3()
etc.
```
The `ma_decoder_init_file()` API will try using the file extension to determine which decoding backend to prefer.
5. Encoding
===========
The `ma_encoding` API is used for writing audio files. The only supported output format is WAV which is achieved via dr_wav which is amalgamated into the
implementation section of miniaudio. This can be disabled by specifying the following option before the implementation of miniaudio:
```c
#define MA_NO_WAV
```
An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data delivered via callbacks with `ma_encoder_init()`. Below is an
example for initializing an encoder to output to a file.
```c
ma_encoder_config config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE);
ma_encoder encoder;
ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder);
if (result != MA_SUCCESS) {
// Error
}
...
ma_encoder_uninit(&encoder);
```
When initializing an encoder you must specify a config which is initialized with `ma_encoder_config_init()`. Here you must specify the file type, the output
sample format, output channel count and output sample rate. The following file types are supported:
+------------------------+-------------+
| Enum | Description |
+------------------------+-------------+
| ma_resource_format_wav | WAV |
+------------------------+-------------+
If the format, channel count or sample rate is not supported by the output file type an error will be returned. The encoder will not perform data conversion so
you will need to convert it before outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the example below:
```c
framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite);
```
Encoders must be uninitialized with `ma_encoder_uninit()`.
6. Data Conversion
==================
A data conversion API is included with miniaudio which supports the majority of data conversion requirements. This supports conversion between sample formats,
channel counts (with channel mapping) and sample rates.
6.1. Sample Format Conversion
-----------------------------
Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()`
to convert between two specific formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use `ma_convert_pcm_frames_format()` to convert
PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count.
6.1.1. Dithering
----------------
Dithering can be set using the ditherMode parameter.
The different dithering modes include the following, in order of efficiency:
+-----------+--------------------------+
| Type | Enum Token |
+-----------+--------------------------+
| None | ma_dither_mode_none |
| Rectangle | ma_dither_mode_rectangle |
| Triangle | ma_dither_mode_triangle |
+-----------+--------------------------+
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it with `ma_audio_buffer_uninit_and_free()`. In the example above,
the memory pointed to by `pExistingData` will be copied into the buffer, which is contrary to the behavior of `ma_audio_buffer_init()`.
An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the cursor moves forward. The last parameter (`loop`) can be
used to determine if the buffer should loop. The return value is the number of frames actually read. If this is less than the number of frames requested it
means the end has been reached. This should never happen if the `loop` parameter is set to true. If you want to manually loop back to the start, you can do so
with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an audio buffer.
```c
ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping);
if (framesRead < desiredFrameCount) {
// If not looping, this means the end has been reached. This should never happen in looping mode with valid input.
}
```
Sometimes you may want to avoid the cost of data movement between the internal buffer and the output buffer. Instead you can use memory mapping to retrieve a
pointer to a segment of data:
```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.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
ma_stream_layout_deinterleaved
} ma_stream_layout;
typedef enum
{
ma_dither_mode_none = 0,
ma_dither_mode_rectangle,
ma_dither_mode_triangle
} ma_dither_mode;
typedef enum
{
/*
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 */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap);
/*
Helper for comparing two channel maps for equality.
This assumes the channel count is the same between the two.
Both channels map buffers must have a capacity of at least `channels`.
*/
MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB);
/*
Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
The channel map buffer must have a capacity of at least `channels`.
*/
MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap);
/*
Helper for determining whether or not a channel is present in the given channel map.
The channel map buffer must have a capacity of at least `channels`.
*/
MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition);
/************************************************************************************************************************************************************
Conversion Helpers
************************************************************************************************************************************************************/
/*
High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to
determine the required size of the output buffer. frameCountOut should be set to the capacity of pOut. If pOut is NULL, frameCountOut is
ignored.
A return value of 0 indicates an error.
This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_data_converter APIs instead.
*/
MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_uint64 frameCountIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn);
MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig);
/************************************************************************************************************************************************************
Ring Buffer
************************************************************************************************************************************************************/
typedef struct
{
void* pBuffer;
ma_uint32 subbufferSizeInBytes;
ma_uint32 subbufferCount;
ma_uint32 subbufferStrideInBytes;
volatile ma_uint32 encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. */
volatile ma_uint32 encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. */
ma_bool32 ownsBuffer : 1; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */
ma_bool32 clearOnWriteAcquire : 1; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */
ma_allocation_callbacks allocationCallbacks;
} ma_rb;
MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB);
MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB);
MA_API void ma_rb_uninit(ma_rb* pRB);
MA_API void ma_rb_reset(ma_rb* pRB);
MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut);
MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut);
MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes);
MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes);
MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB); /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hi...
MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB);
MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB);
MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB);
MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB);
MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex);
MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer);
typedef struct
{
ma_rb rb;
ma_format format;
ma_uint32 channels;
} ma_pcm_rb;
MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallba...
MA_API ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB);
MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB);
MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB);
MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut);
MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut);
MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB); /* Return value is in frames. */
MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB);
MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB);
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB);
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB);
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex);
MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
/************************************************************************************************************************************************************
Miscellaneous Helpers
************************************************************************************************************************************************************/
/*
Retrieves a human readable description of the given result code.
*/
MA_API const char* ma_result_description(ma_result result);
/*
malloc(). Calls MA_MALLOC().
*/
MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
/*
realloc(). Calls MA_REALLOC().
*/
MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
/*
free(). Calls MA_FREE().
*/
MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
/*
Performs an aligned malloc, with the assumption that the alignment is a power of 2.
*/
MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks);
/*
Free's an aligned malloc'd buffer.
*/
MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
/*
Retrieves a friendly name for a format.
*/
MA_API const char* ma_get_format_name(ma_format format);
/*
Blends two frames in floating point format.
*/
MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels);
/*
Retrieves the size of a sample in bytes for the given format.
This API is efficient and is implemented using a lookup table.
Thread Safety: SAFE
This API is pure.
*/
MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format);
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)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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
Whether or not to try auto-starting the JACK server. Defaults to false.
It is recommended that only a single context is active at any given time because it's a bulky data structure which performs run-time linking for the
relevant backends every time it's initialized.
The location of the context cannot change throughout it's lifetime. Consider allocating the `ma_context` object with `malloc()` if this is an issue. The
reason for this is that a pointer to the context is stored in the `ma_device` structure.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*
Clips f32 samples.
*/
MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount);
static MA_INLINE void ma_clip_pcm_frames_f32(float* p, ma_uint64 frameCount, ma_uint32 channels) { ma_clip_samples_f32(p, frameCount*channels); }
/*
Helper for applying a volume factor to samples.
Note that the source and destination buffers can be the same, in which case it'll perform the operation in-place.
*/
MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor);
MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor);
MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor);
MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor);
MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor);
MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor);
MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor);
MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor);
MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor);
MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor);
MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor);
MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
MA_API void ma_apply_volume_factor_pcm_frames(void* pFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor);
/*
Helper for converting a linear factor to gain in decibels.
*/
MA_API float ma_factor_to_gain_db(float factor);
/*
Helper for converting gain in decibels to a linear factor.
*/
MA_API float ma_gain_db_to_factor(float gain);
typedef void ma_data_source;
typedef struct
{
ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
ma_result (* onSeek)(ma_data_source* pDataSource, ma_uint64 frameIndex);
ma_result (* onMap)(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
ma_result (* onUnmap)(ma_data_source* pDataSource, ma_uint64 frameCount);
ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor);
ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength);
} ma_data_source_callbacks;
MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */
MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex);
MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount);
MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor);
MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_uint64 sizeInFrames;
const void* pData; /* If set to NULL, will allocate a block of memory for you. */
ma_allocation_callbacks allocationCallbacks;
} ma_audio_buffer_config;
MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint64 sizeInFrames, const void* pData, const ma_allocation_callbacks* pAllocationCallbacks);
typedef struct
{
ma_data_source_callbacks ds;
ma_format format;
ma_uint32 channels;
ma_uint64 cursor;
ma_uint64 sizeInFrames;
const void* pData;
ma_allocation_callbacks allocationCallbacks;
ma_bool32 ownsData; /* Used to control whether or not miniaudio owns the data buffer. If set to true, pData will be freed in ma_audio_buffer_uninit(). */
ma_uint8 _pExtraData[1]; /* For allocating a buffer with the memory located directly after the other memory of the structure. */
} ma_audio_buffer;
MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer);
MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer);
MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer); /* Always copies the data. Doesn't make sense to use this otherwise. Use ma_audio_buffer_uninit_and_free() to uninit. */
MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer);
MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer);
MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex);
MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount);
MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
MA_API ma_result ma_audio_buffer_at_end(ma_audio_buffer* pAudioBuffer);
MA_API ma_result ma_audio_buffer_get_available_frames(ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames);
/************************************************************************************************************************************************************
VFS
===
The VFS object (virtual file system) is what's used to customize file access. This is useful in cases where stdio FILE* based APIs may not be entirely
appropriate for a given situation.
************************************************************************************************************************************************************/
typedef void ma_vfs;
typedef ma_handle ma_vfs_file;
#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
{
struct
{
ma_vfs* pVFS;
ma_vfs_file file;
} vfs;
struct
{
const ma_uint8* pData;
size_t dataSize;
size_t currentReadPos;
} memory; /* Only used for decoders that were opened against a block of memory. */
} backend;
};
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);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*
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;
ma_encoder_write_pcm_frames_proc onWritePCMFrames;
void* pUserData;
void* pInternalEncoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
void* pFile; /* FILE*. Only used when initialized with ma_encoder_init_file(). */
};
MA_API ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
MA_API void ma_encoder_uninit(ma_encoder* pEncoder);
MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount);
#endif /* MA_NO_ENCODING */
/************************************************************************************************************************************************************
Generation
************************************************************************************************************************************************************/
#ifndef MA_NO_GENERATION
typedef enum
{
ma_waveform_type_sine,
ma_waveform_type_square,
ma_waveform_type_triangle,
ma_waveform_type_sawtooth
} ma_waveform_type;
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_waveform_type type;
double amplitude;
double frequency;
} ma_waveform_config;
MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency);
typedef struct
{
ma_data_source_callbacks ds;
ma_waveform_config config;
double advance;
double time;
} ma_waveform;
MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform);
MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount);
MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex);
MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude);
MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency);
MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate);
typedef enum
{
ma_noise_type_white,
ma_noise_type_pink,
ma_noise_type_brownian
} ma_noise_type;
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_noise_type type;
ma_int32 seed;
double amplitude;
ma_bool32 duplicateChannels;
} ma_noise_config;
MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude);
typedef struct
{
ma_data_source_callbacks ds;
ma_noise_config config;
ma_lcg lcg;
union
{
struct
{
double bin[MA_MAX_CHANNELS][16];
double accumulation[MA_MAX_CHANNELS];
ma_uint32 counter[MA_MAX_CHANNELS];
} pink;
struct
{
double accumulation[MA_MAX_CHANNELS];
} brownian;
} state;
} ma_noise;
MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise);
MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount);
#endif /* MA_NO_GENERATION */
#ifdef __cplusplus
}
#endif
#endif /* miniaudio_h */
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
IMPLEMENTATION
*************************************************************************************************************************************************************
************************************************************************************************************************************************************/
#if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION)
#ifndef miniaudio_c
#define miniaudio_c
#include <assert.h>
#include <limits.h> /* For INT_MAX */
#include <math.h> /* sin(), etc. */
#include <stdarg.h>
#include <stdio.h>
#if !defined(_MSC_VER) && !defined(__DMC__)
#include <strings.h> /* For strcasecmp(). */
#include <wchar.h> /* For wcslen(), wcsrtombs() */
#endif
#ifdef MA_WIN32
#include <windows.h>
#else
#include <stdlib.h> /* For malloc(), free(), wcstombs(). */
#include <string.h> /* For memset() */
#include <sched.h>
#include <sys/time.h> /* select() (used for ma_sleep()). */
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return 22; /* Ran out of room in the output buffer. */
}
*dstEnd = '\0';
/* At this point the string will be reversed. */
dstEnd -= 1;
while (dst < dstEnd) {
char temp = *dst;
*dst = *dstEnd;
*dstEnd = temp;
dst += 1;
dstEnd -= 1;
}
return 0;
}
MA_API int ma_strcmp(const char* str1, const char* str2)
{
if (str1 == str2) return 0;
/* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */
if (str1 == NULL) return -1;
if (str2 == NULL) return 1;
for (;;) {
if (str1[0] == '\0') {
break;
}
if (str1[0] != str2[0]) {
break;
}
str1 += 1;
str2 += 1;
}
return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
}
MA_API int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB)
{
int result;
result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1);
if (result != 0) {
return result;
}
result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1);
if (result != 0) {
return result;
}
return result;
}
MA_API char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks)
{
size_t sz = strlen(src)+1;
char* dst = (char*)ma_malloc(sz, pAllocationCallbacks);
if (dst == NULL) {
return NULL;
}
ma_strcpy_s(dst, sz, src);
return dst;
}
#include <errno.h>
static ma_result ma_result_from_errno(int e)
{
switch (e)
{
case 0: return MA_SUCCESS;
#ifdef EPERM
case EPERM: return MA_INVALID_OPERATION;
#endif
#ifdef ENOENT
case ENOENT: return MA_DOES_NOT_EXIST;
#endif
#ifdef ESRCH
case ESRCH: return MA_DOES_NOT_EXIST;
#endif
#ifdef EINTR
case EINTR: return MA_INTERRUPT;
#endif
#ifdef EIO
case EIO: return MA_IO_ERROR;
#endif
#ifdef ENXIO
case ENXIO: return MA_DOES_NOT_EXIST;
#endif
#ifdef E2BIG
case E2BIG: return MA_INVALID_ARGS;
#endif
#ifdef ENOEXEC
case ENOEXEC: return MA_INVALID_FILE;
#endif
#ifdef EBADF
case EBADF: return MA_INVALID_FILE;
#endif
#ifdef ECHILD
case ECHILD: return MA_ERROR;
#endif
#ifdef EAGAIN
case EAGAIN: return MA_UNAVAILABLE;
#endif
#ifdef ENOMEM
case ENOMEM: return MA_OUT_OF_MEMORY;
#endif
#ifdef EACCES
case EACCES: return MA_ACCESS_DENIED;
#endif
#ifdef EFAULT
case EFAULT: return MA_BAD_ADDRESS;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
#if _MSC_VER && _MSC_VER >= 1400
errno_t err;
#endif
if (ppFile != NULL) {
*ppFile = NULL; /* Safety. */
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return MA_INVALID_ARGS;
}
#if _MSC_VER && _MSC_VER >= 1400
err = fopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return ma_result_from_errno(err);
}
#else
#if defined(_WIN32) || defined(__APPLE__)
*ppFile = fopen(pFilePath, pOpenMode);
#else
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
*ppFile = fopen64(pFilePath, pOpenMode);
#else
*ppFile = fopen(pFilePath, pOpenMode);
#endif
#endif
if (*ppFile == NULL) {
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';
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define c89atomic_exchange_32( dst, src) c89atomic_exchange_explicit_32( dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_exchange_64( dst, src) c89atomic_exchange_explicit_64( dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_exchange_ptr(dst, src) c89atomic_exchange_explicit_ptr(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_strong_8( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_8 ( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_strong_16( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_16( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_strong_32( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_32( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_strong_64( dst, expected, desired) c89atomic_compare_exchange_strong_explicit_64( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_strong_ptr(dst, expected, desired) c89atomic_compare_exchange_strong_explicit_ptr(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_weak_8( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_8 ( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_weak_16( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_16( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_weak_32( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_32( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_weak_64( dst, expected, desired) c89atomic_compare_exchange_weak_explicit_64( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_compare_exchange_weak_ptr(dst, expected, desired) c89atomic_compare_exchange_weak_explicit_ptr(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_add_8( dst, src) c89atomic_fetch_add_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_add_16(dst, src) c89atomic_fetch_add_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_add_32(dst, src) c89atomic_fetch_add_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_add_64(dst, src) c89atomic_fetch_add_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_sub_8( dst, src) c89atomic_fetch_sub_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_sub_16(dst, src) c89atomic_fetch_sub_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_sub_32(dst, src) c89atomic_fetch_sub_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_sub_64(dst, src) c89atomic_fetch_sub_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_or_8( dst, src) c89atomic_fetch_or_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_or_16(dst, src) c89atomic_fetch_or_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_or_32(dst, src) c89atomic_fetch_or_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_or_64(dst, src) c89atomic_fetch_or_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_xor_8( dst, src) c89atomic_fetch_xor_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_xor_16(dst, src) c89atomic_fetch_xor_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_xor_32(dst, src) c89atomic_fetch_xor_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_xor_64(dst, src) c89atomic_fetch_xor_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_and_8( dst, src) c89atomic_fetch_and_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_and_16(dst, src) c89atomic_fetch_and_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_and_32(dst, src) c89atomic_fetch_and_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
#define c89atomic_fetch_and_64(dst, src) c89atomic_fetch_and_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
#if defined(__cplusplus)
}
#endif
#endif
/* c89atomic.h end */
static void* ma__malloc_default(size_t sz, void* pUserData)
{
(void)pUserData;
return MA_MALLOC(sz);
}
static void* ma__realloc_default(void* p, size_t sz, void* pUserData)
{
(void)pUserData;
return MA_REALLOC(p, sz);
}
static void ma__free_default(void* p, void* pUserData)
{
(void)pUserData;
MA_FREE(p);
}
static void* ma__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onMalloc != NULL) {
return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
}
/* Try using realloc(). */
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
}
return NULL;
}
static void* ma__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
}
/* Try emulating realloc() in terms of malloc()/free(). */
if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
void* p2;
p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
if (p2 == NULL) {
return NULL;
}
if (p != NULL) {
MA_COPY_MEMORY(p2, p, szOld);
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
return p2;
}
return NULL;
}
static MA_INLINE void* ma__calloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
{
void* p = ma__malloc_from_callbacks(sz, pAllocationCallbacks);
if (p != NULL) {
MA_ZERO_MEMORY(p, sz);
}
return p;
}
static void ma__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (p == NULL || pAllocationCallbacks == NULL) {
return;
}
if (pAllocationCallbacks->onFree != NULL) {
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
}
static ma_allocation_callbacks ma_allocation_callbacks_init_default(void)
{
ma_allocation_callbacks callbacks;
callbacks.pUserData = NULL;
callbacks.onMalloc = ma__malloc_default;
callbacks.onRealloc = ma__realloc_default;
callbacks.onFree = ma__free_default;
return callbacks;
}
static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst, const ma_allocation_callbacks* pSrc)
{
if (pDst == NULL) {
return MA_INVALID_ARGS;
}
if (pSrc == NULL) {
*pDst = ma_allocation_callbacks_init_default();
} else {
if (pSrc->pUserData == NULL && pSrc->onFree == NULL && pSrc->onMalloc == NULL && pSrc->onRealloc == NULL) {
*pDst = ma_allocation_callbacks_init_default();
} else {
if (pSrc->onFree == NULL || (pSrc->onMalloc == NULL && pSrc->onRealloc == NULL)) {
return MA_INVALID_ARGS; /* Invalid allocation callbacks. */
} else {
*pDst = *pSrc;
}
}
}
return MA_SUCCESS;
}
MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
{
/* 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;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
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);
#endif
}
MA_API ma_result ma_event_init(ma_event* pEvent)
{
if (pEvent == 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_event_init__win32(pEvent);
#endif
#ifdef MA_POSIX
return ma_event_init__posix(pEvent);
#endif
}
#if 0
static ma_result ma_event_alloc_and_init(ma_event** ppEvent, ma_allocation_callbacks* pAllocationCallbacks)
{
ma_result result;
ma_event* pEvent;
if (ppEvent == NULL) {
return MA_INVALID_ARGS;
}
*ppEvent = NULL;
pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/);
if (pEvent == NULL) {
return MA_OUT_OF_MEMORY;
}
result = ma_event_init(pEvent);
if (result != MA_SUCCESS) {
ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/);
return result;
}
*ppEvent = pEvent;
return result;
}
#endif
MA_API void ma_event_uninit(ma_event* pEvent)
{
if (pEvent == NULL) {
return;
}
#ifdef MA_WIN32
ma_event_uninit__win32(pEvent);
#endif
#ifdef MA_POSIX
ma_event_uninit__posix(pEvent);
#endif
}
#if 0
static void ma_event_uninit_and_free(ma_event* pEvent, ma_allocation_callbacks* pAllocationCallbacks)
{
if (pEvent == NULL) {
return;
}
ma_event_uninit(pEvent);
ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/);
}
#endif
MA_API ma_result ma_event_wait(ma_event* pEvent)
{
if (pEvent == 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_event_wait__win32(pEvent);
#endif
#ifdef MA_POSIX
return ma_event_wait__posix(pEvent);
#endif
}
MA_API ma_result ma_event_signal(ma_event* pEvent)
{
if (pEvent == 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_event_signal__win32(pEvent);
#endif
#ifdef MA_POSIX
return ma_event_signal__posix(pEvent);
#endif
}
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. */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
errno = EINVAL;
return -1;
}
for (;;) {
char* pNewTempBuffer = (char*)ma_realloc(pTempBuffer, tempBufferCap, NULL); /* TODO: Add support for custom memory allocators? */
if (pNewTempBuffer == NULL) {
ma_free(pTempBuffer, NULL);
errno = ENOMEM;
return -1; /* Out of memory. */
}
pTempBuffer = pNewTempBuffer;
result = _vsnprintf(pTempBuffer, tempBufferCap, format, args);
ma_free(pTempBuffer, NULL);
if (result != -1) {
break; /* Got it. */
}
/* Buffer wasn't big enough. Ideally it'd be nice to use an error code to know the reason for sure, but this is reliable enough. */
tempBufferCap *= 2;
}
return result;
#endif
}
#endif
/* Posts a formatted log message. */
static void ma_post_log_messagev(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, va_list args)
{
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__)
{
char pFormattedMessage[1024];
vsnprintf(pFormattedMessage, sizeof(pFormattedMessage), pFormat, args);
ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage);
}
#else
{
/*
Without snprintf() we need to first measure the string and then heap allocate it. I'm only aware of Visual Studio having support for this without snprintf(), so we'll
need to restrict this branch to Visual Studio. For other compilers we need to just not support formatted logging because I don't want the security risk of overflowing
a fixed sized stack allocated buffer.
*/
#if defined(_MSC_VER) && _MSC_VER >= 1200 /* 1200 = VC6 */
int formattedLen;
va_list args2;
#if _MSC_VER >= 1800
va_copy(args2, args);
#else
args2 = args;
#endif
formattedLen = ma_vscprintf(pFormat, args2);
va_end(args2);
if (formattedLen > 0) {
char* pFormattedMessage = NULL;
ma_allocation_callbacks* pAllocationCallbacks = NULL;
/* Make sure we have a context so we can allocate memory. */
if (pContext == NULL) {
if (pDevice != NULL) {
pContext = pDevice->pContext;
}
}
if (pContext != NULL) {
pAllocationCallbacks = &pContext->allocationCallbacks;
}
pFormattedMessage = (char*)ma_malloc(formattedLen + 1, pAllocationCallbacks);
if (pFormattedMessage != NULL) {
/* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */
#if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */
vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args);
#else
vsprintf(pFormattedMessage, pFormat, args);
#endif
ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage);
ma_free(pFormattedMessage, pAllocationCallbacks);
}
}
#else
/* Can't do anything because we don't have a safe way of to emulate vsnprintf() without a manual solution. */
(void)pContext;
(void)pDevice;
(void)logLevel;
(void)pFormat;
(void)args;
#endif
}
#endif
}
MA_API void ma_post_log_messagef(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, ...)
{
va_list args;
va_start(args, pFormat);
{
ma_post_log_messagev(pContext, pDevice, logLevel, pFormat, args);
}
va_end(args);
}
/* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */
static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
{
ma_post_log_message(pContext, pDevice, logLevel, message);
return resultCode;
}
static ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
{
return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode);
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
{
UINT winMMDeviceID;
MA_ASSERT(pContext != NULL);
if (shareMode == ma_share_mode_exclusive) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
winMMDeviceID = 0;
if (pDeviceID != NULL) {
winMMDeviceID = (UINT)pDeviceID->winmm;
}
pDeviceInfo->id.winmm = winMMDeviceID;
if (deviceType == ma_device_type_playback) {
MMRESULT result;
MA_WAVEOUTCAPS2A caps;
MA_ZERO_OBJECT(&caps);
result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (WAVEOUTCAPSA*)&caps, sizeof(caps));
if (result == MMSYSERR_NOERROR) {
return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo);
}
} else {
MMRESULT result;
MA_WAVEINCAPS2A caps;
MA_ZERO_OBJECT(&caps);
result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (WAVEINCAPSA*)&caps, sizeof(caps));
if (result == MMSYSERR_NOERROR) {
return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo);
}
}
return MA_NO_DEVICE;
}
static void ma_device_uninit__winmm(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
CloseHandle((HANDLE)pDevice->winmm.hEventCapture);
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
CloseHandle((HANDLE)pDevice->winmm.hEventPlayback);
}
ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */
}
static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
{
const char* errorMsg = "";
ma_result errorCode = MA_ERROR;
ma_result result = MA_SUCCESS;
ma_uint32 heapSize;
UINT winMMDeviceIDPlayback = 0;
UINT winMMDeviceIDCapture = 0;
ma_uint32 periodSizeInMilliseconds;
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->winmm);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
/* No exlusive mode with WinMM. */
if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) ||
((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
if (periodSizeInMilliseconds == 0) {
periodSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->periodSizeInFrames, pConfig->sampleRate);
}
/* WinMM has horrible latency. */
if (pDevice->usingDefaultBufferSize) {
if (pConfig->performanceProfile == ma_performance_profile_low_latency) {
periodSizeInMilliseconds = 40;
} else {
periodSizeInMilliseconds = 400;
}
}
if (pConfig->playback.pDeviceID != NULL) {
winMMDeviceIDPlayback = (UINT)pConfig->playback.pDeviceID->winmm;
}
if (pConfig->capture.pDeviceID != NULL) {
winMMDeviceIDCapture = (UINT)pConfig->capture.pDeviceID->winmm;
}
/* The capture device needs to be initialized first. */
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
WAVEINCAPSA caps;
WAVEFORMATEX wf;
MMRESULT resultMM;
/* We use an event to know when a new fragment needs to be enqueued. */
pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
if (pDevice->winmm.hEventCapture == NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pDevice->capture.internalFormat = ma_format_from_WAVEFORMATEX(&wf);
pDevice->capture.internalChannels = wf.nChannels;
pDevice->capture.internalSampleRate = wf.nSamplesPerSec;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
pDevice->capture.internalPeriods = pConfig->periods;
pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pDevice->capture.internalSampleRate);
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
WAVEOUTCAPSA caps;
WAVEFORMATEX wf;
MMRESULT resultMM;
/* We use an event to know when a new fragment needs to be enqueued. */
pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL);
if (pDevice->winmm.hEventPlayback == NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error;
}
/* The format should be based on the device's actual format. */
if (((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
if (result != MA_SUCCESS) {
errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
goto on_error;
}
resultMM = ((MA_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
if (resultMM != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX(&wf);
pDevice->playback.internalChannels = wf.nChannels;
pDevice->playback.internalSampleRate = wf.nSamplesPerSec;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
pDevice->playback.internalPeriods = pConfig->periods;
pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pDevice->playback.internalSampleRate);
}
/*
The heap allocated data is allocated like so:
[Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer]
*/
heapSize = 0;
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
heapSize += sizeof(WAVEHDR)*pDevice->capture.internalPeriods + (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
heapSize += sizeof(WAVEHDR)*pDevice->playback.internalPeriods + (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
}
pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pContext->allocationCallbacks);
if (pDevice->winmm._pHeapData == NULL) {
errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
goto on_error;
}
MA_ZERO_MEMORY(pDevice->winmm._pHeapData, heapSize);
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 iPeriod;
if (pConfig->deviceType == ma_device_type_capture) {
pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods));
} else {
pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods));
}
/* Prepare headers. */
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalFormat, pDevice->capture.internalChannels);
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod));
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes;
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags = 0L;
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops = 0L;
((MA_PFN_waveInPrepareHeader)pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
/*
The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means
it's unlocked and available for writing. A value of 1 means it's locked.
*/
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0;
}
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 iPeriod;
if (pConfig->deviceType == ma_device_type_playback) {
pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDevice->playback.internalPeriods);
} else {
pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods));
pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods)) + (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeri...
}
/* Prepare headers. */
for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalFormat, pDevice->playback.internalChannels);
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod));
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes;
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags = 0L;
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops = 0L;
((MA_PFN_waveOutPrepareHeader)pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
/*
The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means
it's unlocked and available for writing. A value of 1 means it's locked.
*/
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0;
}
}
return MA_SUCCESS;
on_error:
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->winmm.pWAVEHDRCapture != NULL) {
ma_uint32 iPeriod;
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
((MA_PFN_waveInUnprepareHeader)pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
}
}
((MA_PFN_waveInClose)pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
if (pDevice->winmm.pWAVEHDRCapture != NULL) {
ma_uint32 iPeriod;
for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
((MA_PFN_waveOutUnprepareHeader)pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
}
}
((MA_PFN_waveOutClose)pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
}
ma__free_from_callbacks(pDevice->winmm._pHeapData, &pContext->allocationCallbacks);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode);
}
static ma_result ma_device_stop__winmm(ma_device* pDevice)
{
MMRESULT resultMM;
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->winmm.hDeviceCapture == NULL) {
return MA_INVALID_ARGS;
}
resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture);
if (resultMM != MMSYSERR_NOERROR) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset capture device.", ma_result_from_MMRESULT(resultMM));
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma_uint32 iPeriod;
WAVEHDR* pWAVEHDR;
if (pDevice->winmm.hDevicePlayback == NULL) {
return MA_INVALID_ARGS;
}
/* We need to drain the device. To do this we just loop over each header and if it's locked just wait for the event. */
pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; iPeriod += 1) {
if (pWAVEHDR[iPeriod].dwUser == 1) { /* 1 = locked. */
if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
break; /* An error occurred so just abandon ship and stop the device without draining. */
}
pWAVEHDR[iPeriod].dwUser = 0;
}
}
resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
if (resultMM != MMSYSERR_NOERROR) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM));
}
}
return MA_SUCCESS;
}
static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{
ma_result result = MA_SUCCESS;
MMRESULT resultMM;
ma_uint32 totalFramesWritten;
WAVEHDR* pWAVEHDR;
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pPCMFrames != NULL);
if (pFramesWritten != NULL) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
char** ppDeviceHints;
ma_device_id* pUniqueIDs = NULL;
ma_uint32 uniqueIDCount = 0;
char** ppNextDeviceHint;
MA_ASSERT(pContext != NULL);
MA_ASSERT(callback != NULL);
ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock);
resultALSA = ((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints);
if (resultALSA < 0) {
ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
return ma_result_from_errno(-resultALSA);
}
ppNextDeviceHint = ppDeviceHints;
while (*ppNextDeviceHint != NULL) {
char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
ma_device_type deviceType = ma_device_type_playback;
ma_bool32 stopEnumeration = MA_FALSE;
char hwid[sizeof(pUniqueIDs->alsa)];
ma_device_info deviceInfo;
if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) {
deviceType = ma_device_type_playback;
}
if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) {
deviceType = ma_device_type_capture;
}
if (NAME != NULL) {
if (pContext->alsa.useVerboseDeviceEnumeration) {
/* Verbose mode. Use the name exactly as-is. */
ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
} else {
/* Simplified mode. Use ":%d,%d" format. */
if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
/*
At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
device type and sharing mode.
*/
char* dst = hwid;
char* src = hwid+2;
while ((*dst++ = *src++));
} else {
/* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
}
if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) {
goto next_device; /* The device has already been enumerated. Move on to the next one. */
} else {
/* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */
size_t oldCapacity = sizeof(*pUniqueIDs) * uniqueIDCount;
size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1);
ma_device_id* pNewUniqueIDs = (ma_device_id*)ma__realloc_from_callbacks(pUniqueIDs, newCapacity, oldCapacity, &pContext->allocationCallbacks);
if (pNewUniqueIDs == NULL) {
goto next_device; /* Failed to allocate memory. */
}
pUniqueIDs = pNewUniqueIDs;
MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid));
uniqueIDCount += 1;
}
}
} else {
MA_ZERO_MEMORY(hwid, sizeof(hwid));
}
MA_ZERO_OBJECT(&deviceInfo);
ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1);
/*
DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose
device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish
between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the
description.
The value in DESC seems to be split into two lines, with the first line being the name of the device and the
second line being a description of the device. I don't like having the description be across two lines because
it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line
being put into parentheses. In simplified mode I'm just stripping the second line entirely.
*/
if (DESC != NULL) {
int lfPos;
const char* line2 = ma_find_char(DESC, '\n', &lfPos);
if (line2 != NULL) {
line2 += 1; /* Skip past the new-line character. */
if (pContext->alsa.useVerboseDeviceEnumeration) {
/* Verbose mode. Put the second line in brackets. */
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " (");
ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), line2);
ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")");
} else {
/* Simplified mode. Strip the second line entirely. */
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
}
} else {
/* There's no second line. Just copy the whole description. */
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, (size_t)-1);
}
}
if (!ma_is_device_blacklisted__alsa(deviceType, NAME)) {
cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
}
/*
Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback
again for the other device type in this case. We do this for known devices.
*/
if (cbResult) {
if (ma_is_common_device_name__alsa(NAME)) {
if (deviceType == ma_device_type_playback) {
if (!ma_is_capture_device_blacklisted__alsa(NAME)) {
cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
}
} else {
if (!ma_is_playback_device_blacklisted__alsa(NAME)) {
cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
}
}
}
}
if (cbResult == MA_FALSE) {
stopEnumeration = MA_TRUE;
}
next_device:
free(NAME);
free(DESC);
free(IOID);
ppNextDeviceHint += 1;
/* We need to stop enumeration if the callback returned false. */
if (stopEnumeration) {
break;
}
}
ma__free_from_callbacks(pUniqueIDs, &pContext->allocationCallbacks);
((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints);
ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
return MA_SUCCESS;
}
typedef struct
{
ma_device_type deviceType;
const ma_device_id* pDeviceID;
ma_share_mode shareMode;
ma_device_info* pDeviceInfo;
ma_bool32 foundDevice;
} ma_context_get_device_info_enum_callback_data__alsa;
static ma_bool32 ma_context_get_device_info_enum_callback__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData)
{
ma_context_get_device_info_enum_callback_data__alsa* pData = (ma_context_get_device_info_enum_callback_data__alsa*)pUserData;
MA_ASSERT(pData != NULL);
if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
pData->foundDevice = MA_TRUE;
} else {
if (pData->deviceType == deviceType && ma_context_is_device_id_equal__alsa(pContext, pData->pDeviceID, &pDeviceInfo->id)) {
ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
pData->foundDevice = MA_TRUE;
}
}
/* Keep enumerating until we have found the device. */
return !pData->foundDevice;
}
static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
{
ma_context_get_device_info_enum_callback_data__alsa data;
ma_result result;
int resultALSA;
ma_snd_pcm_t* pPCM;
ma_snd_pcm_hw_params_t* pHWParams;
ma_snd_pcm_format_mask_t* pFormatMask;
int sampleRateDir = 0;
MA_ASSERT(pContext != NULL);
/* We just enumerate to find basic information about the device. */
data.deviceType = deviceType;
data.pDeviceID = pDeviceID;
data.shareMode = shareMode;
data.pDeviceInfo = pDeviceInfo;
data.foundDevice = MA_FALSE;
result = ma_context_enumerate_devices__alsa(pContext, ma_context_get_device_info_enum_callback__alsa, &data);
if (result != MA_SUCCESS) {
return result;
}
if (!data.foundDevice) {
return MA_NO_DEVICE;
}
/* For detailed info we need to open the device. */
result = ma_context_open_pcm__alsa(pContext, shareMode, deviceType, pDeviceID, 0, &pPCM);
if (result != MA_SUCCESS) {
return result;
}
/* We need to initialize a HW parameters object in order to know what formats are supported. */
pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks);
if (pHWParams == NULL) {
return MA_OUT_OF_MEMORY;
}
resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA));
}
((ma_snd_pcm_hw_params_get_channels_min_proc)pContext->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams, &pDeviceInfo->minChannels);
((ma_snd_pcm_hw_params_get_channels_max_proc)pContext->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams, &pDeviceInfo->maxChannels);
((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &pDeviceInfo->minSampleRate, &sampleRateDir);
((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &pDeviceInfo->maxSampleRate, &sampleRateDir);
/* Formats. */
pFormatMask = (ma_snd_pcm_format_mask_t*)ma__calloc_from_callbacks(((ma_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)(), &pContext->allocationCallbacks);
if (pFormatMask == NULL) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
return MA_OUT_OF_MEMORY;
}
((ma_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask);
pDeviceInfo->formatCount = 0;
if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_U8)) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_u8;
}
if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S16_LE)) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s16;
}
if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S24_3LE)) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s24;
}
if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S32_LE)) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s32;
}
if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_FLOAT_LE)) {
pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_f32;
}
ma__free_from_callbacks(pFormatMask, &pContext->allocationCallbacks);
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
return MA_SUCCESS;
}
#if 0
/*
Waits for a number of frames to become available for either capture or playback. The return
value is the number of frames available.
This will return early if the main loop is broken with ma_device__break_main_loop().
*/
static ma_uint32 ma_device__wait_for_frames__alsa(ma_device* pDevice, ma_bool32* pRequiresRestart)
{
MA_ASSERT(pDevice != NULL);
if (pRequiresRestart) *pRequiresRestart = MA_FALSE;
/* I want it so that this function returns the period size in frames. We just wait until that number of frames are available and then return. */
ma_uint32 periodSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods;
while (!pDevice->alsa.breakFromMainLoop) {
ma_snd_pcm_sframes_t framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM);
if (framesAvailable < 0) {
if (framesAvailable == -EPIPE) {
if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MA_TRUE) < 0) {
return 0;
}
/* A device recovery means a restart for mmap mode. */
if (pRequiresRestart) {
*pRequiresRestart = MA_TRUE;
}
/* Try again, but if it fails this time just return an error. */
framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM);
if (framesAvailable < 0) {
return 0;
}
}
}
if (framesAvailable >= periodSizeInFrames) {
return periodSizeInFrames;
}
if (framesAvailable < periodSizeInFrames) {
/* Less than a whole period is available so keep waiting. */
int waitResult = ((ma_snd_pcm_wait_proc)pDevice->pContext->alsa.snd_pcm_wait)((ma_snd_pcm_t*)pDevice->alsa.pPCM, -1);
if (waitResult < 0) {
if (waitResult == -EPIPE) {
if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, waitResult, MA_TRUE) < 0) {
return 0;
}
/* A device recovery means a restart for mmap mode. */
if (pRequiresRestart) {
*pRequiresRestart = MA_TRUE;
}
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_ASSERT(pDevice != NULL);
if ((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) {
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
}
if ((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) {
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
}
}
static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice)
{
ma_result result;
int resultALSA;
ma_snd_pcm_t* pPCM;
ma_bool32 isUsingMMap;
ma_snd_pcm_format_t formatALSA;
ma_share_mode shareMode;
const ma_device_id* pDeviceID;
ma_format internalFormat;
ma_uint32 internalChannels;
ma_uint32 internalSampleRate;
ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_uint32 internalPeriodSizeInFrames;
ma_uint32 internalPeriods;
int openMode;
ma_snd_pcm_hw_params_t* pHWParams;
ma_snd_pcm_sw_params_t* pSWParams;
ma_snd_pcm_uframes_t bufferBoundary;
float bufferSizeScaleFactor;
MA_ASSERT(pContext != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should only be called for playback _or_ capture, never duplex. */
MA_ASSERT(pDevice != NULL);
formatALSA = ma_convert_ma_format_to_alsa_format((deviceType == ma_device_type_capture) ? pConfig->capture.format : pConfig->playback.format);
shareMode = (deviceType == ma_device_type_capture) ? pConfig->capture.shareMode : pConfig->playback.shareMode;
pDeviceID = (deviceType == ma_device_type_capture) ? pConfig->capture.pDeviceID : pConfig->playback.pDeviceID;
openMode = 0;
if (pConfig->alsa.noAutoResample) {
openMode |= MA_SND_PCM_NO_AUTO_RESAMPLE;
}
if (pConfig->alsa.noAutoChannels) {
openMode |= MA_SND_PCM_NO_AUTO_CHANNELS;
}
if (pConfig->alsa.noAutoFormat) {
openMode |= MA_SND_PCM_NO_AUTO_FORMAT;
}
result = ma_context_open_pcm__alsa(pContext, shareMode, deviceType, pDeviceID, openMode, &pPCM);
if (result != MA_SUCCESS) {
return result;
}
/* If using the default buffer size we may want to apply some device-specific scaling for known devices that have peculiar latency characteristics */
bufferSizeScaleFactor = 1;
if (pDevice->usingDefaultBufferSize) {
ma_snd_pcm_info_t* pInfo = (ma_snd_pcm_info_t*)ma__calloc_from_callbacks(((ma_snd_pcm_info_sizeof_proc)pContext->alsa.snd_pcm_info_sizeof)(), &pContext->allocationCallbacks);
if (pInfo == NULL) {
return MA_OUT_OF_MEMORY;
}
/* We may need to scale the size of the buffer depending on the device. */
if (((ma_snd_pcm_info_proc)pContext->alsa.snd_pcm_info)(pPCM, pInfo) == 0) {
const char* deviceName = ((ma_snd_pcm_info_get_name_proc)pContext->alsa.snd_pcm_info_get_name)(pInfo);
if (deviceName != NULL) {
if (ma_strcmp(deviceName, "default") == 0) {
char** ppDeviceHints;
char** ppNextDeviceHint;
/* It's the default device. We need to use DESC from snd_device_name_hint(). */
if (((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) {
ma__free_from_callbacks(pInfo, &pContext->allocationCallbacks);
return MA_NO_BACKEND;
}
ppNextDeviceHint = ppDeviceHints;
while (*ppNextDeviceHint != NULL) {
char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
ma_bool32 foundDevice = MA_FALSE;
if ((deviceType == ma_device_type_playback && (IOID == NULL || ma_strcmp(IOID, "Output") == 0)) ||
(deviceType == ma_device_type_capture && (IOID != NULL && ma_strcmp(IOID, "Input" ) == 0))) {
if (ma_strcmp(NAME, deviceName) == 0) {
bufferSizeScaleFactor = ma_find_default_buffer_size_scale__alsa(DESC);
foundDevice = MA_TRUE;
}
}
free(NAME);
free(DESC);
free(IOID);
ppNextDeviceHint += 1;
if (foundDevice) {
break;
}
}
((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints);
} else {
bufferSizeScaleFactor = ma_find_default_buffer_size_scale__alsa(deviceName);
}
}
}
ma__free_from_callbacks(pInfo, &pContext->allocationCallbacks);
}
/* Hardware parameters. */
pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks);
if (pHWParams == NULL) {
return MA_OUT_OF_MEMORY;
}
resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA));
}
/* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */
isUsingMMap = MA_FALSE;
#if 0 /* NOTE: MMAP mode temporarily disabled. */
if (deviceType != ma_device_type_capture) { /* <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it which means I can't test it... Contributions welcome. */
if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) {
if (((ma_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) {
pDevice->alsa.isUsingMMap = MA_TRUE;
}
}
}
#endif
if (!isUsingMMap) {
resultALSA = ((ma_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_RW_INTERLEAVED);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", ma_result_from_errno(-resultALSA));
}
}
/*
Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't
find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS.
*/
/* Format. */
{
ma_snd_pcm_format_mask_t* pFormatMask;
/* Try getting every supported format first. */
pFormatMask = (ma_snd_pcm_format_mask_t*)ma__calloc_from_callbacks(((ma_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)(), &pContext->allocationCallbacks);
if (pFormatMask == NULL) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return MA_OUT_OF_MEMORY;
}
((ma_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask);
/*
At this point we should have a list of supported formats, so now we need to find the best one. We first check if the requested format is
supported, and if so, use that one. If it's not supported, we just run though a list of formats and try to find the best one.
*/
if (!((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, formatALSA)) {
size_t i;
/* The requested format is not supported so now try running through the list of formats and return the best one. */
ma_snd_pcm_format_t preferredFormatsALSA[] = {
MA_SND_PCM_FORMAT_S16_LE, /* ma_format_s16 */
MA_SND_PCM_FORMAT_FLOAT_LE, /* ma_format_f32 */
MA_SND_PCM_FORMAT_S32_LE, /* ma_format_s32 */
MA_SND_PCM_FORMAT_S24_3LE, /* ma_format_s24 */
MA_SND_PCM_FORMAT_U8 /* ma_format_u8 */
};
if (ma_is_big_endian()) {
preferredFormatsALSA[0] = MA_SND_PCM_FORMAT_S16_BE;
preferredFormatsALSA[1] = MA_SND_PCM_FORMAT_FLOAT_BE;
preferredFormatsALSA[2] = MA_SND_PCM_FORMAT_S32_BE;
preferredFormatsALSA[3] = MA_SND_PCM_FORMAT_S24_3BE;
preferredFormatsALSA[4] = MA_SND_PCM_FORMAT_U8;
}
formatALSA = MA_SND_PCM_FORMAT_UNKNOWN;
for (i = 0; i < (sizeof(preferredFormatsALSA) / sizeof(preferredFormatsALSA[0])); ++i) {
if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, preferredFormatsALSA[i])) {
formatALSA = preferredFormatsALSA[i];
break;
}
}
if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.", MA_FORMAT_NOT_SUPPORTED);
}
}
ma__free_from_callbacks(pFormatMask, &pContext->allocationCallbacks);
pFormatMask = NULL;
resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", ma_result_from_errno(-resultALSA));
}
internalFormat = ma_format_from_alsa(formatALSA);
if (internalFormat == ma_format_unknown) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
}
}
/* Channels. */
{
unsigned int channels = (deviceType == ma_device_type_capture) ? pConfig->capture.channels : pConfig->playback.channels;
resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", ma_result_from_errno(-resultALSA));
}
internalChannels = (ma_uint32)channels;
}
/* Sample Rate */
{
unsigned int sampleRate;
/*
It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes
problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
resampling.
To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly
faster rate.
miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very
good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.
I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce
this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
*/
((ma_snd_pcm_hw_params_set_rate_resample_proc)pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0);
sampleRate = pConfig->sampleRate;
resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", ma_result_from_errno(-resultALSA));
}
internalSampleRate = (ma_uint32)sampleRate;
}
/* Periods. */
{
ma_uint32 periods = pConfig->periods;
resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", ma_result_from_errno(-resultALSA));
}
internalPeriods = periods;
}
/* Buffer Size */
{
ma_snd_pcm_uframes_t actualBufferSizeInFrames = pConfig->periodSizeInFrames * internalPeriods;
if (actualBufferSizeInFrames == 0) {
actualBufferSizeInFrames = ma_scale_buffer_size(ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, internalSampleRate), bufferSizeScaleFactor) * internalPeriods;
}
resultALSA = ((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", ma_result_from_errno(-resultALSA));
}
internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods;
}
/* Apply hardware parameters. */
resultALSA = ((ma_snd_pcm_hw_params_proc)pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams);
if (resultALSA < 0) {
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", ma_result_from_errno(-resultALSA));
}
ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
pHWParams = NULL;
/* Software parameters. */
pSWParams = (ma_snd_pcm_sw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)(), &pContext->allocationCallbacks);
if (pSWParams == NULL) {
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return MA_OUT_OF_MEMORY;
}
resultALSA = ((ma_snd_pcm_sw_params_current_proc)pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams);
if (resultALSA < 0) {
ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", ma_result_from_errno(-resultALSA));
}
resultALSA = ((ma_snd_pcm_sw_params_set_avail_min_proc)pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, ma_prev_power_of_2(internalPeriodSizeInFrames));
if (resultALSA < 0) {
ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", ma_result_from_errno(-resultALSA));
}
resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary);
if (resultALSA < 0) {
bufferBoundary = internalPeriodSizeInFrames * internalPeriods;
}
/*printf("TRACE: bufferBoundary=%ld\n", bufferBoundary);*/
if (deviceType == ma_device_type_playback && !isUsingMMap) { /* Only playback devices in writei/readi mode need a start threshold. */
/*
Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to
the size of a period. But for full-duplex we need to set it such that it is at least two periods.
*/
resultALSA = ((ma_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalPeriodSizeInFrames*2);
if (resultALSA < 0) {
ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", ma_result_from_errno(-resultALSA));
}
resultALSA = ((ma_snd_pcm_sw_params_set_stop_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary);
if (resultALSA < 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */
ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.", ma_result_from_errno(-resultALSA));
}
}
resultALSA = ((ma_snd_pcm_sw_params_proc)pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams);
if (resultALSA < 0) {
ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", ma_result_from_errno(-resultALSA));
}
ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
pSWParams = NULL;
/* Grab the internal channel map. For now we're not going to bother trying to change the channel map and instead just do it ourselves. */
{
ma_snd_pcm_chmap_t* pChmap = ((ma_snd_pcm_get_chmap_proc)pContext->alsa.snd_pcm_get_chmap)(pPCM);
if (pChmap != NULL) {
ma_uint32 iChannel;
/* There are cases where the returned channel map can have a different channel count than was returned by snd_pcm_hw_params_set_channels_near(). */
if (pChmap->channels >= internalChannels) {
/* Drop excess channels. */
for (iChannel = 0; iChannel < internalChannels; ++iChannel) {
internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
}
} else {
ma_uint32 i;
/*
Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate
channels. If validation fails, fall back to defaults.
*/
ma_bool32 isValid = MA_TRUE;
/* Fill with defaults. */
ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
/* Overwrite first pChmap->channels channels. */
for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) {
internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
}
/* Validate. */
for (i = 0; i < internalChannels && isValid; ++i) {
ma_uint32 j;
for (j = i+1; j < internalChannels; ++j) {
if (internalChannelMap[i] == internalChannelMap[j]) {
isValid = MA_FALSE;
break;
}
}
}
/* If our channel map is invalid, fall back to defaults. */
if (!isValid) {
ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
}
}
free(pChmap);
pChmap = NULL;
} else {
/* Could not retrieve the channel map. Fall back to a hard-coded assumption. */
ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
}
}
/* We're done. Prepare the device. */
resultALSA = ((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)(pPCM);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (pDeviceID != NULL && pDeviceID->jack != 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), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
} else {
ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
}
/* Jack only supports f32 and has a specific channel count and sample rate. */
pDeviceInfo->formatCount = 1;
pDeviceInfo->formats[0] = ma_format_f32;
/* The channel count and sample rate can only be determined by opening the device. */
result = ma_context_open_client__jack(pContext, &pClient);
if (result != MA_SUCCESS) {
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result);
}
pDeviceInfo->minSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient);
pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
pDeviceInfo->minChannels = 0;
pDeviceInfo->maxChannels = 0;
ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ((deviceType == ma_device_type_playback) ? ma_JackPortIsInput : ma_JackPortIsOutput));
if (ppPorts == NULL) {
((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
while (ppPorts[pDeviceInfo->minChannels] != NULL) {
pDeviceInfo->minChannels += 1;
pDeviceInfo->maxChannels += 1;
}
((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
(void)pContext;
return MA_SUCCESS;
}
static void ma_device_uninit__jack(ma_device* pDevice)
{
ma_context* pContext;
MA_ASSERT(pDevice != NULL);
pContext = pDevice->pContext;
MA_ASSERT(pContext != NULL);
if (pDevice->jack.pClient != NULL) {
((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDevice->jack.pClient);
}
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->type == ma_device_type_duplex) {
ma_pcm_rb_uninit(&pDevice->jack.duplexRB);
}
}
static void ma_device__jack_shutdown_callback(void* pUserData)
{
/* JACK died. Stop the device. */
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
ma_device_stop(pDevice);
}
static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, void* pUserData)
{
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
size_t newBufferSize = frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks);
if (pNewBuffer == NULL) {
return MA_OUT_OF_MEMORY;
}
ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
pDevice->jack.pIntermediaryBufferCapture = pNewBuffer;
pDevice->playback.internalPeriodSizeInFrames = frameCount;
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
size_t newBufferSize = frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks);
if (pNewBuffer == NULL) {
return MA_OUT_OF_MEMORY;
}
ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer;
pDevice->playback.internalPeriodSizeInFrames = frameCount;
}
return 0;
}
static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* pUserData)
{
ma_device* pDevice;
ma_context* pContext;
ma_uint32 iChannel;
pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
pContext = pDevice->pContext;
MA_ASSERT(pContext != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
/* Channels need to be interleaved. */
for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsCapture[iChannel], frameCount);
if (pSrc != NULL) {
float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel;
ma_jack_nframes_t iFrame;
for (iFrame = 0; iFrame < frameCount; ++iFrame) {
*pDst = *pSrc;
pDst += pDevice->capture.internalChannels;
pSrc += 1;
}
}
}
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_capture(pDevice, frameCount, pDevice->jack.pIntermediaryBufferCapture, &pDevice->jack.duplexRB);
} else {
ma_device__send_frames_to_client(pDevice, frameCount, pDevice->jack.pIntermediaryBufferCapture);
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_playback(pDevice, frameCount, pDevice->jack.pIntermediaryBufferPlayback, &pDevice->jack.duplexRB);
} else {
ma_device__read_frames_from_client(pDevice, frameCount, pDevice->jack.pIntermediaryBufferPlayback);
}
/* Channels need to be deinterleaved. */
for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[iChannel], frameCount);
if (pDst != NULL) {
const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel;
ma_jack_nframes_t iFrame;
for (iFrame = 0; iFrame < frameCount; ++iFrame) {
*pDst = *pSrc;
pDst += 1;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* No exclusive mode with the JACK backend. */
if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) ||
((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
/* Open the client. */
result = ma_context_open_client__jack(pContext, (ma_jack_client_t**)&pDevice->jack.pClient);
if (result != MA_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result);
}
/* Callbacks. */
if (((ma_jack_set_process_callback_proc)pContext->jack.jack_set_process_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_process_callback, pDevice) != 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
if (((ma_jack_set_buffer_size_callback_proc)pContext->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_buffer_size_callback, pDevice) != 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
((ma_jack_on_shutdown_proc)pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice);
/* The buffer size in frames can change. */
periods = pConfig->periods;
periodSizeInFrames = ((ma_jack_get_buffer_size_proc)pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient);
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
const char** ppPorts;
pDevice->capture.internalFormat = ma_format_f32;
pDevice->capture.internalChannels = 0;
pDevice->capture.internalSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
if (ppPorts == NULL) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
while (ppPorts[pDevice->capture.internalChannels] != NULL) {
char name[64];
ma_strcpy_s(name, sizeof(name), "capture");
ma_itoa_s((int)pDevice->capture.internalChannels, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */
pDevice->jack.pPortsCapture[pDevice->capture.internalChannels] = ((ma_jack_port_register_proc)pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0);
if (pDevice->jack.pPortsCapture[pDevice->capture.internalChannels] == NULL) {
((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
ma_device_uninit__jack(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
pDevice->capture.internalChannels += 1;
}
((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->capture.internalPeriods = periods;
pDevice->jack.pIntermediaryBufferCapture = (float*)ma__calloc_from_callbacks(pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels), &pContext->allocationCallba...
if (pDevice->jack.pIntermediaryBufferCapture == NULL) {
ma_device_uninit__jack(pDevice);
return MA_OUT_OF_MEMORY;
}
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
const char** ppPorts;
pDevice->playback.internalFormat = ma_format_f32;
pDevice->playback.internalChannels = 0;
pDevice->playback.internalSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
if (ppPorts == NULL) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
while (ppPorts[pDevice->playback.internalChannels] != NULL) {
char name[64];
ma_strcpy_s(name, sizeof(name), "playback");
ma_itoa_s((int)pDevice->playback.internalChannels, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */
pDevice->jack.pPortsPlayback[pDevice->playback.internalChannels] = ((ma_jack_port_register_proc)pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0);
if (pDevice->jack.pPortsPlayback[pDevice->playback.internalChannels] == NULL) {
((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
ma_device_uninit__jack(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
}
pDevice->playback.internalChannels += 1;
}
((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->playback.internalPeriods = periods;
pDevice->jack.pIntermediaryBufferPlayback = (float*)ma__calloc_from_callbacks(pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels), &pContext->allocationCa...
if (pDevice->jack.pIntermediaryBufferPlayback == NULL) {
ma_device_uninit__jack(pDevice);
return MA_OUT_OF_MEMORY;
}
}
if (pDevice->type == 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);
result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->jack.duplexRB);
if (result != MA_SUCCESS) {
ma_device_uninit__jack(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] 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 marginSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
void* pMarginData;
ma_pcm_rb_acquire_write(&pDevice->jack.duplexRB, &marginSizeInFrames, &pMarginData);
{
MA_ZERO_MEMORY(pMarginData, marginSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
}
ma_pcm_rb_commit_write(&pDevice->jack.duplexRB, marginSizeInFrames, pMarginData);
}
}
return MA_SUCCESS;
}
static ma_result ma_device_start__jack(ma_device* pDevice)
{
ma_context* pContext = pDevice->pContext;
int resultJACK;
size_t i;
resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient);
if (resultJACK != 0) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.", MA_FAILED_TO_START_BACKEND_DEVICE);
}
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
if (ppServerPorts == NULL) {
((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR);
}
for (i = 0; ppServerPorts[i] != NULL; ++i) {
const char* pServerPort = ppServerPorts[i];
const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsCapture[i]);
resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort);
if (resultJACK != 0) {
((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR);
}
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
result = ma_get_AudioObject_uid_as_CFStringRef(pContext, objectID, &uid);
if (result != MA_SUCCESS) {
return result;
}
if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(uid, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
return MA_ERROR;
}
((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(uid);
return MA_SUCCESS;
}
static ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
{
AudioObjectPropertyAddress propAddress;
CFStringRef deviceName = NULL;
UInt32 dataSize;
OSStatus status;
MA_ASSERT(pContext != NULL);
propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
propAddress.mScope = kAudioObjectPropertyScopeGlobal;
propAddress.mElement = kAudioObjectPropertyElementMaster;
dataSize = sizeof(deviceName);
status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName);
if (status != noErr) {
return ma_result_from_OSStatus(status);
}
if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(deviceName, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
return MA_ERROR;
}
((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(deviceName);
return MA_SUCCESS;
}
static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioObjectID deviceObjectID, AudioObjectPropertyScope scope)
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
AudioBufferList* pBufferList;
ma_bool32 isSupported;
MA_ASSERT(pContext != NULL);
/* To know whether or not a device is an input device we need ot look at the stream configuration. If it has an output channel it's a playback device. */
propAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
propAddress.mScope = scope;
propAddress.mElement = kAudioObjectPropertyElementMaster;
status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
if (status != noErr) {
return MA_FALSE;
}
pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(dataSize, &pContext->allocationCallbacks);
if (pBufferList == NULL) {
return MA_FALSE; /* Out of memory. */
}
status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList);
if (status != noErr) {
ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks);
return MA_FALSE;
}
isSupported = MA_FALSE;
if (pBufferList->mNumberBuffers > 0) {
isSupported = MA_TRUE;
}
ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks);
return isSupported;
}
static ma_bool32 ma_does_AudioObject_support_playback(ma_context* pContext, AudioObjectID deviceObjectID)
{
return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeOutput);
}
static ma_bool32 ma_does_AudioObject_support_capture(ma_context* pContext, AudioObjectID deviceObjectID)
{
return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeInput);
}
static ma_result ma_get_AudioObject_stream_descriptions(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pDescriptionCount, AudioStreamRangedDescription** ppDescriptions) /* NOTE: Free the returned pointer with m...
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
AudioStreamRangedDescription* pDescriptions;
MA_ASSERT(pContext != NULL);
MA_ASSERT(pDescriptionCount != NULL);
MA_ASSERT(ppDescriptions != NULL);
/*
TODO: Experiment with kAudioStreamPropertyAvailablePhysicalFormats instead of (or in addition to) kAudioStreamPropertyAvailableVirtualFormats. My
MacBook Pro uses s24/32 format, however, which miniaudio does not currently support.
*/
propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/
propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
propAddress.mElement = kAudioObjectPropertyElementMaster;
status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
if (status != noErr) {
return ma_result_from_OSStatus(status);
}
pDescriptions = (AudioStreamRangedDescription*)ma_malloc(dataSize, &pContext->allocationCallbacks);
if (pDescriptions == NULL) {
return MA_OUT_OF_MEMORY;
}
status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pDescriptions);
if (status != noErr) {
ma_free(pDescriptions, &pContext->allocationCallbacks);
return ma_result_from_OSStatus(status);
}
*pDescriptionCount = dataSize / sizeof(*pDescriptions);
*ppDescriptions = pDescriptions;
return MA_SUCCESS;
}
static ma_result ma_get_AudioObject_channel_layout(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, AudioChannelLayout** ppChannelLayout) /* NOTE: Free the returned pointer with ma_free(). */
{
AudioObjectPropertyAddress propAddress;
UInt32 dataSize;
OSStatus status;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
continue; /* No change to the best format for now. */
}
}
}
} else {
/*
In this case the channel count is different to what the client has requested. If the best so far has the same channel
count as the requested count then it remains the best.
*/
if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
continue;
} else {
/*
This is the case where both have the same sample rate (good) but different channel counts. Right now both have about
the same priority, but we need to compare the format now.
*/
if (thisSampleFormat == bestSampleFormatSoFar) {
if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
bestDeviceFormatSoFar = thisDeviceFormat;
continue;
} else {
continue; /* No change to the best format for now. */
}
}
}
}
}
}
}
*pFormat = bestDeviceFormatSoFar;
ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
return MA_SUCCESS;
}
static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
{
AudioUnitScope deviceScope;
AudioUnitElement deviceBus;
UInt32 channelLayoutSize;
OSStatus status;
AudioChannelLayout* pChannelLayout;
ma_result result;
MA_ASSERT(pContext != NULL);
if (deviceType == ma_device_type_playback) {
deviceScope = kAudioUnitScope_Output;
deviceBus = MA_COREAUDIO_OUTPUT_BUS;
} else {
deviceScope = kAudioUnitScope_Input;
deviceBus = MA_COREAUDIO_INPUT_BUS;
}
status = ((ma_AudioUnitGetPropertyInfo_proc)pContext->coreaudio.AudioUnitGetPropertyInfo)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, &channelLayoutSize, NULL);
if (status != noErr) {
return ma_result_from_OSStatus(status);
}
pChannelLayout = (AudioChannelLayout*)ma__malloc_from_callbacks(channelLayoutSize, &pContext->allocationCallbacks);
if (pChannelLayout == NULL) {
return MA_OUT_OF_MEMORY;
}
status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize);
if (status != noErr) {
ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
return ma_result_from_OSStatus(status);
}
result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
if (result != MA_SUCCESS) {
ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
return result;
}
ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
return MA_SUCCESS;
}
#endif /* MA_APPLE_DESKTOP */
static ma_bool32 ma_context_is_device_id_equal__coreaudio(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 strcmp(pID0->coreaudio, pID1->coreaudio) == 0;
}
#if !defined(MA_APPLE_DESKTOP)
static void ma_AVAudioSessionPortDescription_to_device_info(AVAudioSessionPortDescription* pPortDesc, ma_device_info* pInfo)
{
MA_ZERO_OBJECT(pInfo);
ma_strncpy_s(pInfo->name, sizeof(pInfo->name), [pPortDesc.portName UTF8String], (size_t)-1);
ma_strncpy_s(pInfo->id.coreaudio, sizeof(pInfo->id.coreaudio), [pPortDesc.UID UTF8String], (size_t)-1);
}
#endif
static ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
#if defined(MA_APPLE_DESKTOP)
UInt32 deviceCount;
AudioObjectID* pDeviceObjectIDs;
ma_result result;
UInt32 iDevice;
result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
if (result != MA_SUCCESS) {
return result;
}
for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
ma_device_info info;
MA_ZERO_OBJECT(&info);
if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(info.id.coreaudio), info.id.coreaudio) != MA_SUCCESS) {
continue;
}
if (ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(info.name), info.name) != MA_SUCCESS) {
continue;
}
if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
break;
}
}
if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
break;
}
}
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
g_DeviceTrackingInitCounter_CoreAudio += 1;
}
}
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
return MA_SUCCESS;
}
static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
{
g_DeviceTrackingInitCounter_CoreAudio -= 1;
if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
AudioObjectPropertyAddress propAddress;
propAddress.mScope = kAudioObjectPropertyScopeGlobal;
propAddress.mElement = kAudioObjectPropertyElementMaster;
propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
/* At this point there should be no tracked devices. If not there's an error somewhere. */
if (g_ppTrackedDevices_CoreAudio != NULL) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.", MA_INVALID_OPERATION);
}
ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio);
}
}
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
return MA_SUCCESS;
}
static ma_result ma_device__track__coreaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
{
/* Allocate memory if required. */
if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) {
ma_uint32 oldCap;
ma_uint32 newCap;
ma_device** ppNewDevices;
oldCap = g_TrackedDeviceCap_CoreAudio;
newCap = g_TrackedDeviceCap_CoreAudio * 2;
if (newCap == 0) {
newCap = 1;
}
ppNewDevices = (ma_device**)ma__realloc_from_callbacks(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, sizeof(*g_ppTrackedDevices_CoreAudio)*oldCap, &pDevice->pContext->allocationCallbacks);
if (ppNewDevices == NULL) {
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
return MA_OUT_OF_MEMORY;
}
g_ppTrackedDevices_CoreAudio = ppNewDevices;
g_TrackedDeviceCap_CoreAudio = newCap;
}
g_ppTrackedDevices_CoreAudio[g_TrackedDeviceCount_CoreAudio] = pDevice;
g_TrackedDeviceCount_CoreAudio += 1;
}
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
return MA_SUCCESS;
}
static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
{
ma_uint32 iDevice;
for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
if (g_ppTrackedDevices_CoreAudio[iDevice] == pDevice) {
/* We've found the device. We now need to remove it from the list. */
ma_uint32 jDevice;
for (jDevice = iDevice; jDevice < g_TrackedDeviceCount_CoreAudio-1; jDevice += 1) {
g_ppTrackedDevices_CoreAudio[jDevice] = g_ppTrackedDevices_CoreAudio[jDevice+1];
}
g_TrackedDeviceCount_CoreAudio -= 1;
/* If there's nothing else in the list we need to free memory. */
if (g_TrackedDeviceCount_CoreAudio == 0) {
ma__free_from_callbacks(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks);
g_ppTrackedDevices_CoreAudio = NULL;
g_TrackedDeviceCap_CoreAudio = 0;
}
break;
}
}
}
ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
return MA_SUCCESS;
}
#endif
#if defined(MA_APPLE_MOBILE)
@interface ma_router_change_handler:NSObject {
ma_device* m_pDevice;
}
@end
@implementation ma_router_change_handler
-(id)init:(ma_device*)pDevice
{
self = [super init];
m_pDevice = pDevice;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
return self;
}
-(void)dealloc
{
[self remove_handler];
}
-(void)remove_handler
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVAudioSessionRouteChangeNotification" object:nil];
}
-(void)handle_route_change:(NSNotification*)pNotification
{
AVAudioSession* pSession = [AVAudioSession sharedInstance];
NSInteger reason = [[[pNotification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
switch (reason)
{
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
{
#if defined(MA_DEBUG_OUTPUT)
printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n");
#endif
} break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
{
#if defined(MA_DEBUG_OUTPUT)
printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n");
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#endif
} break;
case AVAudioSessionRouteChangeReasonCategoryChange:
{
#if defined(MA_DEBUG_OUTPUT)
printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n");
#endif
} break;
case AVAudioSessionRouteChangeReasonUnknown:
default:
{
#if defined(MA_DEBUG_OUTPUT)
printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n");
#endif
} break;
}
m_pDevice->sampleRate = (ma_uint32)pSession.sampleRate;
if (m_pDevice->type == ma_device_type_capture || m_pDevice->type == ma_device_type_duplex) {
m_pDevice->capture.channels = (ma_uint32)pSession.inputNumberOfChannels;
ma_device__post_init_setup(m_pDevice, ma_device_type_capture);
}
if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) {
m_pDevice->playback.channels = (ma_uint32)pSession.outputNumberOfChannels;
ma_device__post_init_setup(m_pDevice, ma_device_type_playback);
}
}
@end
#endif
static void ma_device_uninit__coreaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED);
#if defined(MA_APPLE_DESKTOP)
/*
Make sure we're no longer tracking the device. It doesn't matter if we call this for a non-default device because it'll
just gracefully ignore it.
*/
ma_device__untrack__coreaudio(pDevice);
#endif
#if defined(MA_APPLE_MOBILE)
if (pDevice->coreaudio.pRouteChangeHandler != NULL) {
ma_router_change_handler* pRouteChangeHandler = (__bridge_transfer ma_router_change_handler*)pDevice->coreaudio.pRouteChangeHandler;
[pRouteChangeHandler remove_handler];
}
#endif
if (pDevice->coreaudio.audioUnitCapture != NULL) {
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
}
if (pDevice->coreaudio.audioUnitPlayback != NULL) {
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
}
if (pDevice->coreaudio.pAudioBufferList) {
ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->type == ma_device_type_duplex) {
ma_pcm_rb_uninit(&pDevice->coreaudio.duplexRB);
}
}
typedef struct
{
/* Input. */
ma_format formatIn;
ma_uint32 channelsIn;
ma_uint32 sampleRateIn;
ma_channel channelMapIn[MA_MAX_CHANNELS];
ma_uint32 periodSizeInFramesIn;
ma_uint32 periodSizeInMillisecondsIn;
ma_uint32 periodsIn;
ma_bool32 usingDefaultFormat;
ma_bool32 usingDefaultChannels;
ma_bool32 usingDefaultSampleRate;
ma_bool32 usingDefaultChannelMap;
ma_share_mode shareMode;
ma_bool32 registerStopEvent;
/* Output. */
#if defined(MA_APPLE_DESKTOP)
AudioObjectID deviceObjectID;
#endif
AudioComponent component;
AudioUnit audioUnit;
AudioBufferList* pAudioBufferList; /* Only used for input devices. */
ma_format formatOut;
ma_uint32 channelsOut;
ma_uint32 sampleRateOut;
ma_channel channelMapOut[MA_MAX_CHANNELS];
ma_uint32 periodSizeInFramesOut;
ma_uint32 periodsOut;
char deviceName[256];
} ma_device_init_internal_data__coreaudio;
static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* inten...
{
ma_result result;
OSStatus status;
UInt32 enableIOFlag;
AudioStreamBasicDescription bestFormat;
ma_uint32 actualPeriodSizeInFrames;
AURenderCallbackStruct callbackInfo;
#if defined(MA_APPLE_DESKTOP)
AudioObjectID deviceObjectID;
#endif
/* This API should only be used for a single device type: playback or capture. No full-duplex mode. */
if (deviceType == ma_device_type_duplex) {
return MA_INVALID_ARGS;
}
MA_ASSERT(pContext != NULL);
MA_ASSERT(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#if defined(MA_APPLE_DESKTOP)
if (actualPeriodSizeInFrames == 0) {
actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
}
result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
if (result != MA_SUCCESS) {
return result;
}
pData->periodSizeInFramesOut = actualPeriodSizeInFrames;
#else
actualPeriodSizeInFrames = 2048;
pData->periodSizeInFramesOut = actualPeriodSizeInFrames;
#endif
/*
During testing I discovered that the buffer size can be too big. You'll get an error like this:
kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=512
Note how inFramesToProcess is smaller than mMaxFramesPerSlice. To fix, we need to set kAudioUnitProperty_MaximumFramesPerSlice to that
of the size of our buffer, or do it the other way around and set our buffer size to the kAudioUnitProperty_MaximumFramesPerSlice.
*/
{
/*AudioUnitScope propScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
AudioUnitElement propBus = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, propScope, propBus, &actualBufferSizeInFrames, sizeof(actualBufferSizeInFrames));
if (status != noErr) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return ma_result_from_OSStatus(status);
}*/
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, sizeof(actualPeriodSizeInFrames));
if (status != noErr) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return ma_result_from_OSStatus(status);
}
}
/* We need a buffer list if this is an input device. We render into this in the input callback. */
if (deviceType == ma_device_type_capture) {
ma_bool32 isInterleaved = (bestFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
size_t allocationSize;
AudioBufferList* pBufferList;
allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */
if (isInterleaved) {
/* Interleaved case. This is the simple case because we just have one buffer. */
allocationSize += sizeof(AudioBuffer) * 1;
allocationSize += actualPeriodSizeInFrames * ma_get_bytes_per_frame(pData->formatOut, pData->channelsOut);
} else {
/* Non-interleaved case. This is the more complex case because there's more than one buffer. */
allocationSize += sizeof(AudioBuffer) * pData->channelsOut;
allocationSize += actualPeriodSizeInFrames * ma_get_bytes_per_sample(pData->formatOut) * pData->channelsOut;
}
pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(allocationSize, &pContext->allocationCallbacks);
if (pBufferList == NULL) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return MA_OUT_OF_MEMORY;
}
if (isInterleaved) {
pBufferList->mNumberBuffers = 1;
pBufferList->mBuffers[0].mNumberChannels = pData->channelsOut;
pBufferList->mBuffers[0].mDataByteSize = actualPeriodSizeInFrames * ma_get_bytes_per_frame(pData->formatOut, pData->channelsOut);
pBufferList->mBuffers[0].mData = (ma_uint8*)pBufferList + sizeof(AudioBufferList);
} else {
ma_uint32 iBuffer;
pBufferList->mNumberBuffers = pData->channelsOut;
for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
pBufferList->mBuffers[iBuffer].mNumberChannels = 1;
pBufferList->mBuffers[iBuffer].mDataByteSize = actualPeriodSizeInFrames * ma_get_bytes_per_sample(pData->formatOut);
pBufferList->mBuffers[iBuffer].mData = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * pData->channelsOut)) + (actualPeriodSizeInFrames * ma_get_bytes_per_sample(pData->form...
}
}
pData->pAudioBufferList = pBufferList;
}
/* Callbacks. */
callbackInfo.inputProcRefCon = pDevice_DoNotReference;
if (deviceType == ma_device_type_playback) {
callbackInfo.inputProc = ma_on_output__coreaudio;
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, MA_COREAUDIO_OUTPUT_BUS, &callbackInfo, sizeof(callbackInfo));
if (status != noErr) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return ma_result_from_OSStatus(status);
}
} else {
callbackInfo.inputProc = ma_on_input__coreaudio;
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, MA_COREAUDIO_INPUT_BUS, &callbackInfo, sizeof(callbackInfo));
if (status != noErr) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return ma_result_from_OSStatus(status);
}
}
/* We need to listen for stop events. */
if (pData->registerStopEvent) {
status = ((ma_AudioUnitAddPropertyListener_proc)pContext->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit, kAudioOutputUnitProperty_IsRunning, on_start_stop__coreaudio, pDevice_DoNotReference);
if (status != noErr) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return ma_result_from_OSStatus(status);
}
}
/* Initialize the audio unit. */
status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit);
if (status != noErr) {
ma__free_from_callbacks(pData->pAudioBufferList, &pContext->allocationCallbacks);
pData->pAudioBufferList = NULL;
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return ma_result_from_OSStatus(status);
}
/* Grab the name. */
#if defined(MA_APPLE_DESKTOP)
ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pData->deviceName), pData->deviceName);
#else
if (deviceType == ma_device_type_playback) {
ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
} else {
ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_CAPTURE_DEVICE_NAME);
}
#endif
return result;
}
#if defined(MA_APPLE_DESKTOP)
static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit)
{
ma_device_init_internal_data__coreaudio data;
ma_result result;
/* This should only be called for playback or capture, not duplex. */
if (deviceType == ma_device_type_duplex) {
return MA_INVALID_ARGS;
}
if (deviceType == ma_device_type_capture) {
data.formatIn = pDevice->capture.format;
data.channelsIn = pDevice->capture.channels;
data.sampleRateIn = pDevice->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
data.shareMode = pDevice->capture.shareMode;
data.registerStopEvent = MA_TRUE;
if (disposePreviousAudioUnit) {
((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
((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);
}
} else if (deviceType == ma_device_type_playback) {
data.formatIn = pDevice->playback.format;
data.channelsIn = pDevice->playback.channels;
data.sampleRateIn = pDevice->sampleRate;
MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
data.shareMode = pDevice->playback.shareMode;
data.registerStopEvent = (pDevice->type != ma_device_type_duplex);
if (disposePreviousAudioUnit) {
((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
}
}
data.periodSizeInFramesIn = pDevice->coreaudio.originalPeriodSizeInFrames;
data.periodSizeInMillisecondsIn = pDevice->coreaudio.originalPeriodSizeInMilliseconds;
data.periodsIn = pDevice->coreaudio.originalPeriods;
/* Need at least 3 periods for duplex. */
if (data.periodsIn < 3 && pDevice->type == ma_device_type_duplex) {
data.periodsIn = 3;
}
result = ma_device_init_internal__coreaudio(pDevice->pContext, deviceType, NULL, &data, (void*)pDevice);
if (result != MA_SUCCESS) {
return result;
}
if (deviceType == ma_device_type_capture) {
#if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
#endif
pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
pDevice->capture.internalFormat = data.formatOut;
pDevice->capture.internalChannels = data.channelsOut;
pDevice->capture.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->capture.internalPeriods = data.periodsOut;
} else if (deviceType == ma_device_type_playback) {
#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;
}
return MA_SUCCESS;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pConfig->capture.pDeviceID, &data, (void*)pDevice);
if (result != MA_SUCCESS) {
return result;
}
pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL);
#if defined(MA_APPLE_DESKTOP)
pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
#endif
pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
pDevice->capture.internalFormat = data.formatOut;
pDevice->capture.internalChannels = data.channelsOut;
pDevice->capture.internalSampleRate = data.sampleRateOut;
MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
pDevice->capture.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->capture.pDeviceID == NULL) {
ma_device__track__coreaudio(pDevice);
}
#endif
}
/* Playback. */
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_device_init_internal_data__coreaudio data;
data.formatIn = pConfig->playback.format;
data.channelsIn = pConfig->playback.channels;
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);
}
}
/*
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (resultSL != SL_RESULT_SUCCESS) {
return;
}
pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods;
}
static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
{
ma_device* pDevice = (ma_device*)pUserData;
size_t periodSizeInBytes;
ma_uint8* pBuffer;
SLresult resultSL;
MA_ASSERT(pDevice != NULL);
(void)pBufferQueue;
/* Don't do anything if the device is not started. */
if (pDevice->state != MA_STATE_STARTED) {
return;
}
/* Don't do anything if the device is being drained. */
if (pDevice->opensl.isDrainingPlayback) {
return;
}
periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes);
if (pDevice->type == ma_device_type_duplex) {
ma_device__handle_duplex_callback_playback(pDevice, pDevice->playback.internalPeriodSizeInFrames, pBuffer, &pDevice->opensl.duplexRB);
} else {
ma_device__read_frames_from_client(pDevice, pDevice->playback.internalPeriodSizeInFrames, pBuffer);
}
resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes);
if (resultSL != SL_RESULT_SUCCESS) {
return;
}
pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods;
}
#endif
static void ma_device_uninit__opensl(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before uninitializing the device. */
if (g_maOpenSLInitCounter == 0) {
return;
}
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->opensl.pAudioRecorderObj) {
MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj);
}
ma__free_from_callbacks(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
if (pDevice->opensl.pAudioPlayerObj) {
MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj);
}
if (pDevice->opensl.pOutputMixObj) {
MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj);
}
ma__free_from_callbacks(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks);
}
if (pDevice->type == ma_device_type_duplex) {
ma_pcm_rb_uninit(&pDevice->opensl.duplexRB);
}
}
#if defined(MA_ANDROID) && __ANDROID_API__ >= 21
typedef SLAndroidDataFormat_PCM_EX ma_SLDataFormat_PCM;
#else
typedef SLDataFormat_PCM ma_SLDataFormat_PCM;
#endif
static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* channelMap, ma_SLDataFormat_PCM* pDataFormat)
{
#if defined(MA_ANDROID) && __ANDROID_API__ >= 21
if (format == ma_format_f32) {
pDataFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pDataFormat->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
} else {
pDataFormat->formatType = SL_DATAFORMAT_PCM;
}
#else
pDataFormat->formatType = SL_DATAFORMAT_PCM;
#endif
pDataFormat->numChannels = channels;
((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */
pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8;
pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels);
pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
/*
Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html
- Only mono and stereo is supported.
- Only u8 and s16 formats are supported.
- Maximum sample rate of 48000.
*/
#ifdef MA_ANDROID
if (pDataFormat->numChannels > 2) {
pDataFormat->numChannels = 2;
}
#if __ANDROID_API__ >= 21
if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
/* It's floating point. */
MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
if (pDataFormat->bitsPerSample > 32) {
pDataFormat->bitsPerSample = 32;
}
} else {
if (pDataFormat->bitsPerSample > 16) {
pDataFormat->bitsPerSample = 16;
}
}
#else
if (pDataFormat->bitsPerSample > 16) {
pDataFormat->bitsPerSample = 16;
}
#endif
if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec > SL_SAMPLINGRATE_48) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
source.pLocator = &locatorDevice;
source.pFormat = NULL;
sink.pLocator = &queue;
sink.pFormat = (SLDataFormat_PCM*)&pcm;
resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) {
/* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
pcm.formatType = SL_DATAFORMAT_PCM;
pcm.numChannels = 1;
((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
pcm.bitsPerSample = 16;
pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
}
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pContext->opensl.SL_IID_RECORD, &pDevice->opensl.pAudioRecorder);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL));
}
/* The internal format is determined by the "pcm" object. */
ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->capture.internalFormat, &pDevice->capture.internalChannels, &pDevice->capture.internalSampleRate, pDevice->capture.internalChannelMap, ma_countof(pDevice->capture.internalChannelMap));
/* Buffer. */
periodSizeInFrames = pConfig->periodSizeInFrames;
if (periodSizeInFrames == 0) {
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pDevice->capture.internalSampleRate);
}
pDevice->capture.internalPeriods = pConfig->periods;
pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->opensl.currentBufferIndexCapture = 0;
bufferSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels) * pDevice->capture.internalPeriods;
pDevice->opensl.pBufferCapture = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pContext->allocationCallbacks);
if (pDevice->opensl.pBufferCapture == NULL) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY);
}
MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes);
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_SLDataFormat_PCM pcm;
SLDataSource source;
SLDataLocator_OutputMix outmixLocator;
SLDataSink sink;
ma_SLDataFormat_PCM_init__opensl(pConfig->playback.format, pConfig->playback.channels, pConfig->sampleRate, pConfig->playback.channelMap, &pcm);
resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, (SLInterfaceID)pContext->opensl.SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL));
}
/* Set the output device. */
if (pConfig->playback.pDeviceID != NULL) {
SLuint32 deviceID_OpenSL = pConfig->playback.pDeviceID->opensl;
MA_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &deviceID_OpenSL);
}
source.pLocator = &queue;
source.pFormat = (SLDataFormat_PCM*)&pcm;
outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
outmixLocator.outputMix = (SLObjectItf)pDevice->opensl.pOutputMixObj;
sink.pLocator = &outmixLocator;
sink.pFormat = NULL;
resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) {
/* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
pcm.formatType = SL_DATAFORMAT_PCM;
pcm.numChannels = 2;
((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16;
pcm.bitsPerSample = 16;
pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
}
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pContext->opensl.SL_IID_PLAY, &pDevice->opensl.pAudioPlayer);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
}
resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice);
if (resultSL != SL_RESULT_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL));
}
/* The internal format is determined by the "pcm" object. */
ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->playback.internalFormat, &pDevice->playback.internalChannels, &pDevice->playback.internalSampleRate, pDevice->playback.internalChannelMap, ma_countof(pDevice->playback.internalChannelMap...
/* Buffer. */
periodSizeInFrames = pConfig->periodSizeInFrames;
if (periodSizeInFrames == 0) {
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pDevice->playback.internalSampleRate);
}
pDevice->playback.internalPeriods = pConfig->periods;
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->opensl.currentBufferIndexPlayback = 0;
bufferSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels) * pDevice->playback.internalPeriods;
pDevice->opensl.pBufferPlayback = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pContext->allocationCallbacks);
if (pDevice->opensl.pBufferPlayback == NULL) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY);
}
MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes);
}
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->opensl.duplexRB);
if (result != MA_SUCCESS) {
ma_device_uninit__opensl(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] 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 marginSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
void* pMarginData;
ma_pcm_rb_acquire_write(&pDevice->opensl.duplexRB, &marginSizeInFrames, &pMarginData);
{
MA_ZERO_MEMORY(pMarginData, marginSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
}
ma_pcm_rb_commit_write(&pDevice->opensl.duplexRB, marginSizeInFrames, pMarginData);
}
}
return MA_SUCCESS;
#else
return MA_NO_BACKEND; /* Non-Android implementations are not supported. */
#endif
}
static ma_result ma_device_start__opensl(ma_device* pDevice)
{
SLresult resultSL;
size_t periodSizeInBytes;
ma_uint32 iPeriod;
MA_ASSERT(pDevice != NULL);
MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to start the device. */
if (g_maOpenSLInitCounter == 0) {
return MA_INVALID_OPERATION;
}
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING);
if (resultSL != SL_RESULT_SUCCESS) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.", ma_result_from_OpenSL(resultSL));
}
periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes);
if (resultSL != SL_RESULT_SUCCESS) {
MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", ma_result_from_OpenSL(resultSL));
}
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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;
#endif
#ifdef MA_HAS_JACK
case ma_backend_jack:
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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;
}
static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
{
/*
We need to insert the device info into our main internal buffer. Where it goes depends on the device type. If it's a capture device
it's just appended to the end. If it's a playback device it's inserted just before the first capture device.
*/
/*
First make sure we have room. Since the number of devices we add to the list is usually relatively small I've decided to use a
simple fixed size increment for buffer expansion.
*/
const ma_uint32 bufferExpansionCount = 2;
const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount;
if (pContext->deviceInfoCapacity >= totalDeviceInfoCount) {
ma_uint32 oldCapacity = pContext->deviceInfoCapacity;
ma_uint32 newCapacity = oldCapacity + bufferExpansionCount;
ma_device_info* pNewInfos = (ma_device_info*)ma__realloc_from_callbacks(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, sizeof(*pContext->pDeviceInfos)*oldCapacity, &pContext->allocationCallbacks);
if (pNewInfos == NULL) {
return MA_FALSE; /* Out of memory. */
}
pContext->pDeviceInfos = pNewInfos;
pContext->deviceInfoCapacity = newCapacity;
}
if (deviceType == ma_device_type_playback) {
/* Playback. Insert just before the first capture device. */
/* The first thing to do is move all of the capture devices down a slot. */
ma_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount;
size_t iCaptureDevice;
for (iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) {
pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1];
}
/* Now just insert where the first capture device was before moving it down a slot. */
pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo;
pContext->playbackDeviceInfoCount += 1;
} else {
/* Capture. Insert at the end. */
pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo;
pContext->captureDeviceInfoCount += 1;
}
(void)pUserData;
return MA_TRUE;
}
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)
{
ma_result result;
/* Safety. */
if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL;
if (pPlaybackDeviceCount != NULL) *pPlaybackDeviceCount = 0;
if (ppCaptureDeviceInfos != NULL) *ppCaptureDeviceInfos = NULL;
if (pCaptureDeviceCount != NULL) *pCaptureDeviceCount = 0;
if (pContext == NULL || pContext->onEnumDevices == NULL) {
return MA_INVALID_ARGS;
}
/* Note that we don't use ma_context_enumerate_devices() here because we want to do locking at a higher level. */
ma_mutex_lock(&pContext->deviceEnumLock);
{
/* Reset everything first. */
pContext->playbackDeviceInfoCount = 0;
pContext->captureDeviceInfoCount = 0;
/* Now enumerate over available devices. */
result = pContext->onEnumDevices(pContext, ma_context_get_devices__enum_callback, NULL);
if (result == MA_SUCCESS) {
/* Playback devices. */
if (ppPlaybackDeviceInfos != NULL) {
*ppPlaybackDeviceInfos = pContext->pDeviceInfos;
}
if (pPlaybackDeviceCount != NULL) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
}
/* 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) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (result != MA_SUCCESS) {
return 0; /* Failed to initialize the data converter. */
}
if (pOut == NULL) {
frameCountOut = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn);
} else {
result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut);
if (result != MA_SUCCESS) {
frameCountOut = 0;
}
}
ma_data_converter_uninit(&converter);
return frameCountOut;
}
/**************************************************************************************************************************************************************
Ring Buffer
**************************************************************************************************************************************************************/
static MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset)
{
return encodedOffset & 0x7FFFFFFF;
}
static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffset)
{
return encodedOffset & 0x80000000;
}
static MA_INLINE void* ma_rb__get_read_ptr(ma_rb* pRB)
{
MA_ASSERT(pRB != NULL);
return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(pRB->encodedReadOffset));
}
static MA_INLINE void* ma_rb__get_write_ptr(ma_rb* pRB)
{
MA_ASSERT(pRB != NULL);
return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(pRB->encodedWriteOffset));
}
static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag)
{
return offsetLoopFlag | offsetInBytes;
}
static MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32* pOffsetInBytes, ma_uint32* pOffsetLoopFlag)
{
MA_ASSERT(pOffsetInBytes != NULL);
MA_ASSERT(pOffsetLoopFlag != NULL);
*pOffsetInBytes = ma_rb__extract_offset_in_bytes(encodedOffset);
*pOffsetLoopFlag = ma_rb__extract_offset_loop_flag(encodedOffset);
}
MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB)
{
ma_result result;
const ma_uint32 maxSubBufferSize = 0x7FFFFFFF - (MA_SIMD_ALIGNMENT-1);
if (pRB == NULL) {
return MA_INVALID_ARGS;
}
if (subbufferSizeInBytes == 0 || subbufferCount == 0) {
return MA_INVALID_ARGS;
}
if (subbufferSizeInBytes > maxSubBufferSize) {
return MA_INVALID_ARGS; /* Maximum buffer size is ~2GB. The most significant bit is a flag for use internally. */
}
MA_ZERO_OBJECT(pRB);
result = ma_allocation_callbacks_init_copy(&pRB->allocationCallbacks, pAllocationCallbacks);
if (result != MA_SUCCESS) {
return result;
}
pRB->subbufferSizeInBytes = (ma_uint32)subbufferSizeInBytes;
pRB->subbufferCount = (ma_uint32)subbufferCount;
if (pOptionalPreallocatedBuffer != NULL) {
pRB->subbufferStrideInBytes = (ma_uint32)subbufferStrideInBytes;
pRB->pBuffer = pOptionalPreallocatedBuffer;
} else {
size_t bufferSizeInBytes;
/*
Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this
we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT.
*/
pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT;
bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes;
pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks);
if (pRB->pBuffer == NULL) {
return MA_OUT_OF_MEMORY;
}
MA_ZERO_MEMORY(pRB->pBuffer, bufferSizeInBytes);
pRB->ownsBuffer = MA_TRUE;
}
return MA_SUCCESS;
}
MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB)
{
return ma_rb_init_ex(bufferSizeInBytes, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
}
MA_API void ma_rb_uninit(ma_rb* pRB)
{
if (pRB == NULL) {
return;
}
if (pRB->ownsBuffer) {
ma_aligned_free(pRB->pBuffer, &pRB->allocationCallbacks);
}
}
MA_API void ma_rb_reset(ma_rb* pRB)
{
if (pRB == NULL) {
return;
}
pRB->encodedReadOffset = 0;
pRB->encodedWriteOffset = 0;
}
MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
{
ma_uint32 writeOffset;
ma_uint32 writeOffsetInBytes;
ma_uint32 writeOffsetLoopFlag;
ma_uint32 readOffset;
ma_uint32 readOffsetInBytes;
ma_uint32 readOffsetLoopFlag;
size_t bytesAvailable;
size_t bytesRequested;
if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
return MA_INVALID_ARGS;
}
/* The returned buffer should never move ahead of the write pointer. */
writeOffset = pRB->encodedWriteOffset;
ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
readOffset = pRB->encodedReadOffset;
ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
/*
The number of bytes available depends on whether or not the read and write pointers are on the same loop iteration. If so, we
can only read up to the write pointer. If not, we can only read up to the end of the buffer.
*/
if (readOffsetLoopFlag == writeOffsetLoopFlag) {
bytesAvailable = writeOffsetInBytes - readOffsetInBytes;
} else {
bytesAvailable = pRB->subbufferSizeInBytes - readOffsetInBytes;
}
bytesRequested = *pSizeInBytes;
if (bytesRequested > bytesAvailable) {
bytesRequested = bytesAvailable;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return dist;
}
MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB)
{
if (pRB == NULL) {
return 0;
}
return (ma_uint32)(ma_rb_get_subbuffer_size(pRB) - ma_rb_pointer_distance(pRB));
}
MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB)
{
if (pRB == NULL) {
return 0;
}
return pRB->subbufferSizeInBytes;
}
MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB)
{
if (pRB == NULL) {
return 0;
}
if (pRB->subbufferStrideInBytes == 0) {
return (size_t)pRB->subbufferSizeInBytes;
}
return (size_t)pRB->subbufferStrideInBytes;
}
MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex)
{
if (pRB == NULL) {
return 0;
}
return subbufferIndex * ma_rb_get_subbuffer_stride(pRB);
}
MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer)
{
if (pRB == NULL) {
return NULL;
}
return ma_offset_ptr(pBuffer, ma_rb_get_subbuffer_offset(pRB, subbufferIndex));
}
static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB)
{
MA_ASSERT(pRB != NULL);
return ma_get_bytes_per_frame(pRB->format, pRB->channels);
}
MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallba...
{
ma_uint32 bpf;
ma_result result;
if (pRB == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pRB);
bpf = ma_get_bytes_per_frame(format, channels);
if (bpf == 0) {
return MA_INVALID_ARGS;
}
result = ma_rb_init_ex(subbufferSizeInFrames*bpf, subbufferCount, subbufferStrideInFrames*bpf, pOptionalPreallocatedBuffer, pAllocationCallbacks, &pRB->rb);
if (result != MA_SUCCESS) {
return result;
}
pRB->format = format;
pRB->channels = channels;
return MA_SUCCESS;
}
MA_API ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB)
{
return ma_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
}
MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB)
{
if (pRB == NULL) {
return;
}
ma_rb_uninit(&pRB->rb);
}
MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB)
{
if (pRB == NULL) {
return;
}
ma_rb_reset(&pRB->rb);
}
MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
{
size_t sizeInBytes;
ma_result result;
if (pRB == NULL || pSizeInFrames == NULL) {
return MA_INVALID_ARGS;
}
sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
result = ma_rb_acquire_read(&pRB->rb, &sizeInBytes, ppBufferOut);
if (result != MA_SUCCESS) {
return result;
}
*pSizeInFrames = (ma_uint32)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB));
return MA_SUCCESS;
}
MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut)
{
if (pRB == NULL) {
return MA_INVALID_ARGS;
}
return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut);
}
MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
{
size_t sizeInBytes;
ma_result result;
if (pRB == NULL) {
return MA_INVALID_ARGS;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
case MA_IS_DIRECTORY: return "Is a directory";
case MA_DIRECTORY_NOT_EMPTY: return "Directory not empty";
case MA_END_OF_FILE: return "End of file";
case MA_NO_SPACE: return "No space available";
case MA_BUSY: return "Device or resource busy";
case MA_IO_ERROR: return "Input/output error";
case MA_INTERRUPT: return "Interrupted";
case MA_UNAVAILABLE: return "Resource unavailable";
case MA_ALREADY_IN_USE: return "Resource already in use";
case MA_BAD_ADDRESS: return "Bad address";
case MA_BAD_SEEK: return "Illegal seek";
case MA_BAD_PIPE: return "Broken pipe";
case MA_DEADLOCK: return "Deadlock";
case MA_TOO_MANY_LINKS: return "Too many links";
case MA_NOT_IMPLEMENTED: return "Not implemented";
case MA_NO_MESSAGE: return "No message of desired type";
case MA_BAD_MESSAGE: return "Invalid message";
case MA_NO_DATA_AVAILABLE: return "No data available";
case MA_INVALID_DATA: return "Invalid data";
case MA_TIMEOUT: return "Timeout";
case MA_NO_NETWORK: return "Network unavailable";
case MA_NOT_UNIQUE: return "Not unique";
case MA_NOT_SOCKET: return "Socket operation on non-socket";
case MA_NO_ADDRESS: return "Destination address required";
case MA_BAD_PROTOCOL: return "Protocol wrong type for socket";
case MA_PROTOCOL_UNAVAILABLE: return "Protocol not available";
case MA_PROTOCOL_NOT_SUPPORTED: return "Protocol not supported";
case MA_PROTOCOL_FAMILY_NOT_SUPPORTED: return "Protocol family not supported";
case MA_ADDRESS_FAMILY_NOT_SUPPORTED: return "Address family not supported";
case MA_SOCKET_NOT_SUPPORTED: return "Socket type not supported";
case MA_CONNECTION_RESET: return "Connection reset";
case MA_ALREADY_CONNECTED: return "Already connected";
case MA_NOT_CONNECTED: return "Not connected";
case MA_CONNECTION_REFUSED: return "Connection refused";
case MA_NO_HOST: return "No host";
case MA_IN_PROGRESS: return "Operation in progress";
case MA_CANCELLED: return "Operation cancelled";
case MA_MEMORY_ALREADY_MAPPED: return "Memory already mapped";
case MA_AT_END: return "Reached end of collection";
case MA_FORMAT_NOT_SUPPORTED: return "Format not supported";
case MA_DEVICE_TYPE_NOT_SUPPORTED: return "Device type not supported";
case MA_SHARE_MODE_NOT_SUPPORTED: return "Share mode not supported";
case MA_NO_BACKEND: return "No backend";
case MA_NO_DEVICE: return "No device";
case MA_API_NOT_FOUND: return "API not found";
case MA_INVALID_DEVICE_CONFIG: return "Invalid device config";
case MA_DEVICE_NOT_INITIALIZED: return "Device not initialized";
case MA_DEVICE_NOT_STARTED: return "Device not started";
case MA_FAILED_TO_INIT_BACKEND: return "Failed to initialize backend";
case MA_FAILED_TO_OPEN_BACKEND_DEVICE: return "Failed to open backend device";
case MA_FAILED_TO_START_BACKEND_DEVICE: return "Failed to start backend device";
case MA_FAILED_TO_STOP_BACKEND_DEVICE: return "Failed to stop backend device";
default: return "Unknown error";
}
}
MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
return ma__malloc_from_callbacks(sz, pAllocationCallbacks);
} else {
return ma__malloc_default(sz, NULL);
}
}
MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(p, sz, pAllocationCallbacks->pUserData);
} else {
return NULL; /* This requires a native implementation of realloc(). */
}
} else {
return ma__realloc_default(p, sz, NULL);
}
}
MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
ma__free_from_callbacks(p, pAllocationCallbacks);
} else {
ma__free_default(p, NULL);
}
}
MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks)
{
size_t extraBytes;
void* pUnaligned;
void* pAligned;
if (alignment == 0) {
return 0;
}
extraBytes = alignment-1 + sizeof(void*);
pUnaligned = ma_malloc(sz + extraBytes, pAllocationCallbacks);
if (pUnaligned == NULL) {
return NULL;
}
pAligned = (void*)(((ma_uintptr)pUnaligned + extraBytes) & ~((ma_uintptr)(alignment-1)));
((void**)pAligned)[-1] = pUnaligned;
return pAligned;
}
MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_free(((void**)p)[-1], pAllocationCallbacks);
}
MA_API const char* ma_get_format_name(ma_format format)
{
switch (format)
{
case ma_format_unknown: return "Unknown";
case ma_format_u8: return "8-bit Unsigned Integer";
case ma_format_s16: return "16-bit Signed Integer";
case ma_format_s24: return "24-bit Signed Integer (Tightly Packed)";
case ma_format_s32: return "32-bit Signed Integer";
case ma_format_f32: return "32-bit IEEE Floating Point";
default: return "Invalid";
}
}
MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels)
{
ma_uint32 i;
for (i = 0; i < channels; ++i) {
pOut[i] = ma_mix_f32(pInA[i], pInB[i], factor);
}
}
MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format)
{
ma_uint32 sizes[] = {
0, /* unknown */
1, /* u8 */
2, /* s16 */
3, /* s24 */
4, /* s32 */
4, /* f32 */
};
return sizes[format];
}
MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop)
{
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCallbacks == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onRead == NULL) {
return MA_NOT_IMPLEMENTED;
}
/* A very small optimization for the non looping case. */
if (loop == MA_FALSE) {
return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead);
} else {
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
if (ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate) != MA_SUCCESS) {
return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); /* We don't have a way to retrieve the data format which means we don't know how to offset the output buffer. Just read as much as we can. */
} else {
ma_result result = MA_SUCCESS;
ma_uint64 totalFramesProcessed;
void* pRunningFramesOut = pFramesOut;
totalFramesProcessed = 0;
while (totalFramesProcessed < frameCount) {
ma_uint64 framesProcessed;
ma_uint64 framesRemaining = frameCount - totalFramesProcessed;
result = pCallbacks->onRead(pDataSource, pRunningFramesOut, framesRemaining, &framesProcessed);
totalFramesProcessed += framesProcessed;
/*
If we encounted an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is
not necessarily considered an error.
*/
if (result != MA_SUCCESS && result != MA_AT_END) {
break;
}
/*
We can determine if we've reached the end by checking the return value of the onRead() callback. If it's less than what we requested it means
we've reached the end. To loop back to the start, all we need to do is seek back to the first frame.
*/
if (framesProcessed < framesRemaining || result == MA_AT_END) {
if (ma_data_source_seek_to_pcm_frame(pDataSource, 0) != MA_SUCCESS) {
break;
}
}
if (pRunningFramesOut != NULL) {
pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels));
}
}
if (pFramesRead != NULL) {
*pFramesRead = totalFramesProcessed;
}
return result;
}
}
}
MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop)
{
return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked, loop);
}
MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCallbacks == NULL || pCallbacks->onSeek == NULL) {
return MA_INVALID_ARGS;
}
return pCallbacks->onSeek(pDataSource, frameIndex);
}
MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount)
{
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCallbacks == NULL || pCallbacks->onMap == NULL) {
return MA_INVALID_ARGS;
}
return pCallbacks->onMap(pDataSource, ppFramesOut, pFrameCount);
}
MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount)
{
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCallbacks == NULL || pCallbacks->onUnmap == NULL) {
return MA_INVALID_ARGS;
}
return pCallbacks->onUnmap(pDataSource, frameCount);
}
MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
{
ma_result result;
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCallbacks == NULL || pCallbacks->onGetDataFormat == NULL) {
return MA_INVALID_ARGS;
}
result = pCallbacks->onGetDataFormat(pDataSource, &format, &channels, &sampleRate);
if (result != MA_SUCCESS) {
return result;
}
if (pFormat != NULL) {
*pFormat = format;
}
if (pChannels != NULL) {
*pChannels = channels;
}
if (pSampleRate != NULL) {
*pSampleRate = sampleRate;
}
return MA_SUCCESS;
}
MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor)
{
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0;
if (pCallbacks == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onGetCursor == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onGetCursor(pDataSource, pCursor);
}
MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength)
{
ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
if (pLength == NULL) {
return MA_INVALID_ARGS;
}
*pLength = 0;
if (pCallbacks == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onGetLength == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onGetLength(pDataSource, pLength);
}
MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint64 sizeInFrames, const void* pData, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_audio_buffer_config config;
MA_ZERO_OBJECT(&config);
config.format = format;
config.channels = channels;
config.sizeInFrames = sizeInFrames;
config.pData = pData;
ma_allocation_callbacks_init_copy(&config.allocationCallbacks, pAllocationCallbacks);
return config;
}
static ma_result ma_audio_buffer__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames((ma_audio_buffer*)pDataSource, pFramesOut, frameCount, MA_FALSE);
if (pFramesRead != NULL) {
*pFramesRead = framesRead;
}
if (framesRead < frameCount) {
return MA_AT_END;
}
return MA_SUCCESS;
}
static ma_result ma_audio_buffer__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
return ma_audio_buffer_seek_to_pcm_frame((ma_audio_buffer*)pDataSource, frameIndex);
}
static ma_result ma_audio_buffer__data_source_on_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount)
{
return ma_audio_buffer_map((ma_audio_buffer*)pDataSource, ppFramesOut, pFrameCount);
}
static ma_result ma_audio_buffer__data_source_on_unmap(ma_data_source* pDataSource, ma_uint64 frameCount)
{
return ma_audio_buffer_unmap((ma_audio_buffer*)pDataSource, frameCount);
}
static ma_result ma_audio_buffer__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
{
ma_audio_buffer* pAudioBuffer = (ma_audio_buffer*)pDataSource;
*pFormat = pAudioBuffer->format;
*pChannels = pAudioBuffer->channels;
*pSampleRate = 0; /* There is no notion of a sample rate with audio buffers. */
return MA_SUCCESS;
}
static ma_result ma_audio_buffer__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
ma_audio_buffer* pAudioBuffer = (ma_audio_buffer*)pDataSource;
*pCursor = pAudioBuffer->cursor;
return MA_SUCCESS;
}
static ma_result ma_audio_buffer__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
ma_audio_buffer* pAudioBuffer = (ma_audio_buffer*)pDataSource;
*pLength = pAudioBuffer->sizeInFrames;
return MA_SUCCESS;
}
static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, ma_bool32 doCopy, ma_audio_buffer* pAudioBuffer)
{
if (pAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_MEMORY(pAudioBuffer, sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData)); /* Safety. Don't overwrite the extra data. */
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->sizeInFrames == 0) {
return MA_INVALID_ARGS; /* Not allowing buffer sizes of 0 frames. */
}
pAudioBuffer->ds.onRead = ma_audio_buffer__data_source_on_read;
pAudioBuffer->ds.onSeek = ma_audio_buffer__data_source_on_seek;
pAudioBuffer->ds.onMap = ma_audio_buffer__data_source_on_map;
pAudioBuffer->ds.onUnmap = ma_audio_buffer__data_source_on_unmap;
pAudioBuffer->ds.onGetDataFormat = ma_audio_buffer__data_source_on_get_data_format;
pAudioBuffer->ds.onGetCursor = ma_audio_buffer__data_source_on_get_cursor;
pAudioBuffer->ds.onGetLength = ma_audio_buffer__data_source_on_get_length;
pAudioBuffer->format = pConfig->format;
pAudioBuffer->channels = pConfig->channels;
pAudioBuffer->cursor = 0;
pAudioBuffer->sizeInFrames = pConfig->sizeInFrames;
pAudioBuffer->pData = NULL; /* Set properly later. */
ma_allocation_callbacks_init_copy(&pAudioBuffer->allocationCallbacks, &pConfig->allocationCallbacks);
if (doCopy) {
ma_uint64 allocationSizeInBytes;
void* pData;
allocationSizeInBytes = pAudioBuffer->sizeInFrames * ma_get_bytes_per_frame(pAudioBuffer->format, pAudioBuffer->channels);
if (allocationSizeInBytes > MA_SIZE_MAX) {
return MA_OUT_OF_MEMORY; /* Too big. */
}
pData = ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks); /* Safe cast to size_t. */
if (pData == NULL) {
return MA_OUT_OF_MEMORY;
}
if (pConfig->pData != NULL) {
ma_copy_pcm_frames(pData, pConfig->pData, pAudioBuffer->sizeInFrames, pAudioBuffer->format, pAudioBuffer->channels);
} else {
ma_silence_pcm_frames(pData, pAudioBuffer->sizeInFrames, pAudioBuffer->format, pAudioBuffer->channels);
}
pAudioBuffer->pData = pData;
pAudioBuffer->ownsData = MA_TRUE;
} else {
pAudioBuffer->pData = pConfig->pData;
pAudioBuffer->ownsData = MA_FALSE;
}
return MA_SUCCESS;
}
static void ma_audio_buffer_uninit_ex(ma_audio_buffer* pAudioBuffer, ma_bool32 doFree)
{
if (pAudioBuffer == NULL) {
return;
}
if (pAudioBuffer->ownsData && pAudioBuffer->pData != &pAudioBuffer->_pExtraData[0]) {
ma__free_from_callbacks((void*)pAudioBuffer->pData, &pAudioBuffer->allocationCallbacks); /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */
}
if (doFree) {
ma_allocation_callbacks allocationCallbacks = pAudioBuffer->allocationCallbacks;
ma__free_from_callbacks(pAudioBuffer, &allocationCallbacks);
}
}
MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer)
{
return ma_audio_buffer_init_ex(pConfig, MA_FALSE, pAudioBuffer);
}
MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer)
{
return ma_audio_buffer_init_ex(pConfig, MA_TRUE, pAudioBuffer);
}
MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer)
{
ma_result result;
ma_audio_buffer* pAudioBuffer;
ma_audio_buffer_config innerConfig; /* We'll be making some changes to the config, so need to make a copy. */
ma_uint64 allocationSizeInBytes;
if (ppAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
*ppAudioBuffer = NULL; /* Safety. */
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
innerConfig = *pConfig;
ma_allocation_callbacks_init_copy(&innerConfig.allocationCallbacks, &pConfig->allocationCallbacks);
allocationSizeInBytes = sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData) + (pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels));
if (allocationSizeInBytes > MA_SIZE_MAX) {
return MA_OUT_OF_MEMORY; /* Too big. */
}
pAudioBuffer = (ma_audio_buffer*)ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks); /* Safe cast to size_t. */
if (pAudioBuffer == NULL) {
return MA_OUT_OF_MEMORY;
}
if (pConfig->pData != NULL) {
ma_copy_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
} else {
ma_silence_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->sizeInFrames, pConfig->format, pConfig->channels);
}
innerConfig.pData = &pAudioBuffer->_pExtraData[0];
result = ma_audio_buffer_init_ex(&innerConfig, MA_FALSE, pAudioBuffer);
if (result != MA_SUCCESS) {
ma__free_from_callbacks(pAudioBuffer, &innerConfig.allocationCallbacks);
return result;
}
*ppAudioBuffer = pAudioBuffer;
return MA_SUCCESS;
}
MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer)
{
ma_audio_buffer_uninit_ex(pAudioBuffer, MA_FALSE);
}
MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer)
{
ma_audio_buffer_uninit_ex(pAudioBuffer, MA_TRUE);
}
MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop)
{
ma_uint64 totalFramesRead = 0;
if (pAudioBuffer == NULL) {
return 0;
}
if (frameCount == 0) {
return 0;
}
while (totalFramesRead < frameCount) {
ma_uint64 framesAvailable = pAudioBuffer->sizeInFrames - pAudioBuffer->cursor;
ma_uint64 framesRemaining = frameCount - totalFramesRead;
ma_uint64 framesToRead;
framesToRead = framesRemaining;
if (framesToRead > framesAvailable) {
framesToRead = framesAvailable;
}
if (pFramesOut != NULL) {
ma_copy_pcm_frames(pFramesOut, ma_offset_ptr(pAudioBuffer->pData, pAudioBuffer->cursor * ma_get_bytes_per_frame(pAudioBuffer->format, pAudioBuffer->channels)), frameCount, pAudioBuffer->format, pAudioBuffer->channels);
}
totalFramesRead += framesToRead;
pAudioBuffer->cursor += framesToRead;
if (pAudioBuffer->cursor == pAudioBuffer->sizeInFrames) {
if (loop) {
pAudioBuffer->cursor = 0;
} else {
break; /* We've reached the end and we're not looping. Done. */
}
}
MA_ASSERT(pAudioBuffer->cursor < pAudioBuffer->sizeInFrames);
}
return totalFramesRead;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
ma_uint64 framesAvailable;
if (pAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
framesAvailable = pAudioBuffer->sizeInFrames - pAudioBuffer->cursor;
if (frameCount > framesAvailable) {
return MA_INVALID_ARGS; /* The frame count was too big. This should never happen in an unmapping. Need to make sure the caller is aware of this. */
}
pAudioBuffer->cursor += frameCount;
if (pAudioBuffer->cursor == pAudioBuffer->sizeInFrames) {
return MA_AT_END; /* Successful. Need to tell the caller that the end has been reached so that it can loop if desired. */
} else {
return MA_SUCCESS;
}
}
MA_API ma_result ma_audio_buffer_at_end(ma_audio_buffer* pAudioBuffer)
{
if (pAudioBuffer == NULL) {
return MA_FALSE;
}
return pAudioBuffer->cursor == pAudioBuffer->sizeInFrames;
}
MA_API ma_result ma_audio_buffer_get_available_frames(ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames)
{
if (pAvailableFrames == NULL) {
return MA_INVALID_ARGS;
}
*pAvailableFrames = 0;
if (pAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
if (pAudioBuffer->sizeInFrames <= pAudioBuffer->cursor) {
*pAvailableFrames = 0;
} else {
*pAvailableFrames = pAudioBuffer->sizeInFrames - pAudioBuffer->cursor;
}
return MA_SUCCESS;
}
/**************************************************************************************************************************************************************
VFS
**************************************************************************************************************************************************************/
MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pFile == NULL) {
return MA_INVALID_ARGS;
}
*pFile = NULL;
if (pVFS == NULL || pFilePath == NULL || openMode == 0) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onOpen == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onOpen(pVFS, pFilePath, openMode, pFile);
}
MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pFile == NULL) {
return MA_INVALID_ARGS;
}
*pFile = NULL;
if (pVFS == NULL || pFilePath == NULL || openMode == 0) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onOpenW == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onOpenW(pVFS, pFilePath, openMode, pFile);
}
MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pVFS == NULL || file == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onClose == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onClose(pVFS, file);
}
MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pBytesRead != NULL) {
*pBytesRead = 0;
}
if (pVFS == NULL || file == NULL || pDst == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onRead == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, 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_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pBytesWritten != NULL) {
*pBytesWritten = 0;
}
if (pVFS == NULL || file == NULL || pSrc == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onWrite == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onWrite(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
}
MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pVFS == NULL || file == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onSeek == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onSeek(pVFS, file, offset, origin);
}
MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0;
if (pVFS == NULL || file == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onTell == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onTell(pVFS, file, pCursor);
}
MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pInfo == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pInfo);
if (pVFS == NULL || file == NULL) {
return MA_INVALID_ARGS;
}
if (pCallbacks->onInfo == NULL) {
return MA_NOT_IMPLEMENTED;
}
return pCallbacks->onInfo(pVFS, file, pInfo);
}
static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks, ma_uint32 allocationType)
{
ma_result result;
ma_vfs_file file;
ma_file_info info;
void* pData;
size_t bytesRead;
(void)allocationType;
if (ppData != NULL) {
*ppData = NULL;
}
if (pSize != NULL) {
*pSize = 0;
}
if (ppData == NULL) {
return MA_INVALID_ARGS;
}
result = ma_vfs_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
if (result != MA_SUCCESS) {
return result;
}
result = ma_vfs_info(pVFS, file, &info);
if (result != MA_SUCCESS) {
ma_vfs_close(pVFS, file);
return result;
}
if (info.sizeInBytes > MA_SIZE_MAX) {
ma_vfs_close(pVFS, file);
return MA_TOO_BIG;
}
pData = ma__malloc_from_callbacks((size_t)info.sizeInBytes, pAllocationCallbacks); /* Safe cast. */
if (pData == NULL) {
ma_vfs_close(pVFS, file);
return result;
}
result = ma_vfs_read(pVFS, file, pData, (size_t)info.sizeInBytes, &bytesRead); /* Safe cast. */
ma_vfs_close(pVFS, file);
if (result != MA_SUCCESS) {
ma__free_from_callbacks(pData, pAllocationCallbacks);
return result;
}
if (pSize != NULL) {
*pSize = bytesRead;
}
MA_ASSERT(ppData != NULL);
*ppData = pData;
return MA_SUCCESS;
}
ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks)
{
return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/);
}
#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
static void ma_default_vfs__get_open_settings_win32(ma_uint32 openMode, DWORD* pDesiredAccess, DWORD* pShareMode, DWORD* pCreationDisposition)
{
*pDesiredAccess = 0;
if ((openMode & MA_OPEN_MODE_READ) != 0) {
*pDesiredAccess |= GENERIC_READ;
}
if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
*pDesiredAccess |= GENERIC_WRITE;
}
*pShareMode = 0;
if ((openMode & MA_OPEN_MODE_READ) != 0) {
*pShareMode |= FILE_SHARE_READ;
}
if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
*pCreationDisposition = CREATE_ALWAYS; /* Opening in write mode. Truncate. */
} else {
*pCreationDisposition = OPEN_EXISTING; /* Opening in read mode. File must exist. */
}
}
static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
{
HANDLE hFile;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
(void)pVFS;
ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
hFile = CreateFileA(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return ma_result_from_GetLastError(GetLastError());
}
*pFile = hFile;
return MA_SUCCESS;
}
static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
{
HANDLE hFile;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
(void)pVFS;
ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
return ma_default_vfs_write__win32(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
#else
return ma_default_vfs_write__stdio(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
#endif
}
static ma_result ma_default_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
{
if (file == NULL) {
return MA_INVALID_ARGS;
}
#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
return ma_default_vfs_seek__win32(pVFS, file, offset, origin);
#else
return ma_default_vfs_seek__stdio(pVFS, file, offset, origin);
#endif
}
static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
{
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0;
if (file == NULL) {
return MA_INVALID_ARGS;
}
#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
return ma_default_vfs_tell__win32(pVFS, file, pCursor);
#else
return ma_default_vfs_tell__stdio(pVFS, file, pCursor);
#endif
}
static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
{
if (pInfo == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pInfo);
if (file == NULL) {
return MA_INVALID_ARGS;
}
#if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
return ma_default_vfs_info__win32(pVFS, file, pInfo);
#else
return ma_default_vfs_info__stdio(pVFS, file, pInfo);
#endif
}
MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pVFS == NULL) {
return MA_INVALID_ARGS;
}
pVFS->cb.onOpen = ma_default_vfs_open;
pVFS->cb.onOpenW = ma_default_vfs_open_w;
pVFS->cb.onClose = ma_default_vfs_close;
pVFS->cb.onRead = ma_default_vfs_read;
pVFS->cb.onWrite = ma_default_vfs_write;
pVFS->cb.onSeek = ma_default_vfs_seek;
pVFS->cb.onTell = ma_default_vfs_tell;
pVFS->cb.onInfo = ma_default_vfs_info;
ma_allocation_callbacks_init_copy(&pVFS->allocationCallbacks, pAllocationCallbacks);
return MA_SUCCESS;
}
/**************************************************************************************************************************************************************
Decoding and Encoding Headers. These are auto-generated from a tool.
**************************************************************************************************************************************************************/
#if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING))
/* dr_wav_h begin */
#ifndef dr_wav_h
#define dr_wav_h
#ifdef __cplusplus
extern "C" {
#endif
#define DRWAV_STRINGIFY(x) #x
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
#define DRWAV_VERSION_MAJOR 0
#define DRWAV_VERSION_MINOR 12
#define DRWAV_VERSION_REVISION 12
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
#include <stddef.h>
typedef signed char drwav_int8;
typedef unsigned char drwav_uint8;
typedef signed short drwav_int16;
typedef unsigned short drwav_uint16;
typedef signed int drwav_int32;
typedef unsigned int drwav_uint32;
#if defined(_MSC_VER)
typedef signed __int64 drwav_int64;
typedef unsigned __int64 drwav_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 drwav_int64;
typedef unsigned long long drwav_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 drwav_uint64 drwav_uintptr;
#else
typedef drwav_uint32 drwav_uintptr;
#endif
typedef drwav_uint8 drwav_bool8;
typedef drwav_uint32 drwav_bool32;
#define DRWAV_TRUE 1
#define DRWAV_FALSE 0
#if !defined(DRWAV_API)
#if defined(DRWAV_DLL)
#if defined(_WIN32)
#define DRWAV_DLL_IMPORT __declspec(dllimport)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define DRWAV_MEMORY_ALREADY_MAPPED -52
#define DRWAV_AT_END -53
#define DR_WAVE_FORMAT_PCM 0x1
#define DR_WAVE_FORMAT_ADPCM 0x2
#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
#define DR_WAVE_FORMAT_ALAW 0x6
#define DR_WAVE_FORMAT_MULAW 0x7
#define DR_WAVE_FORMAT_DVI_ADPCM 0x11
#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE
#ifndef DRWAV_MAX_SMPL_LOOPS
#define DRWAV_MAX_SMPL_LOOPS 1
#endif
#define DRWAV_SEQUENTIAL 0x00000001
DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
DRWAV_API const char* drwav_version_string(void);
typedef enum
{
drwav_seek_origin_start,
drwav_seek_origin_current
} drwav_seek_origin;
typedef enum
{
drwav_container_riff,
drwav_container_w64,
drwav_container_rf64
} drwav_container;
typedef struct
{
union
{
drwav_uint8 fourcc[4];
drwav_uint8 guid[16];
} id;
drwav_uint64 sizeInBytes;
unsigned int paddingSize;
} drwav_chunk_header;
typedef struct
{
drwav_uint16 formatTag;
drwav_uint16 channels;
drwav_uint32 sampleRate;
drwav_uint32 avgBytesPerSec;
drwav_uint16 blockAlign;
drwav_uint16 bitsPerSample;
drwav_uint16 extendedSize;
drwav_uint16 validBitsPerSample;
drwav_uint32 channelMask;
drwav_uint8 subFormat[16];
} drwav_fmt;
DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT);
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);
} drwav_allocation_callbacks;
typedef struct
{
const drwav_uint8* data;
size_t dataSize;
size_t currentReadPos;
} drwav__memory_stream;
typedef struct
{
void** ppData;
size_t* pDataSize;
size_t dataSize;
size_t dataCapacity;
size_t currentWritePos;
} drwav__memory_stream_write;
typedef struct
{
drwav_container container;
drwav_uint32 format;
drwav_uint32 channels;
drwav_uint32 sampleRate;
drwav_uint32 bitsPerSample;
} drwav_data_format;
typedef struct
{
drwav_uint32 cuePointId;
drwav_uint32 type;
drwav_uint32 start;
drwav_uint32 end;
drwav_uint32 fraction;
drwav_uint32 playCount;
} drwav_smpl_loop;
typedef struct
{
drwav_uint32 manufacturer;
drwav_uint32 product;
drwav_uint32 samplePeriod;
drwav_uint32 midiUnityNotes;
drwav_uint32 midiPitchFraction;
drwav_uint32 smpteFormat;
drwav_uint32 smpteOffset;
drwav_uint32 numSampleLoops;
drwav_uint32 samplerData;
drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS];
} drwav_smpl;
typedef struct
{
drwav_read_proc onRead;
drwav_write_proc onWrite;
drwav_seek_proc onSeek;
void* pUserData;
drwav_allocation_callbacks allocationCallbacks;
drwav_container container;
drwav_fmt fmt;
drwav_uint32 sampleRate;
drwav_uint16 channels;
drwav_uint16 bitsPerSample;
drwav_uint16 translatedFormatTag;
drwav_uint64 totalPCMFrameCount;
drwav_uint64 dataChunkDataSize;
drwav_uint64 dataChunkDataPos;
drwav_uint64 bytesRemaining;
drwav_uint64 dataChunkDataSizeTargetWrite;
drwav_bool32 isSequentialWrite;
drwav_smpl smpl;
drwav__memory_stream memoryStream;
drwav__memory_stream_write memoryStreamWrite;
struct
{
drwav_uint64 iCurrentPCMFrame;
} compressed;
struct
{
drwav_uint32 bytesRemainingInBlock;
drwav_uint16 predictor[2];
drwav_int32 delta[2];
drwav_int32 cachedFrames[4];
drwav_uint32 cachedFrameCount;
drwav_int32 prevFrames[2][2];
} msadpcm;
struct
{
drwav_uint32 bytesRemainingInBlock;
drwav_int32 predictor[2];
drwav_int32 stepIndex[2];
drwav_int32 cachedFrames[16];
drwav_uint32 cachedFrameCount;
} ima;
} drwav;
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
DRWAV_API drwav_result drwav_uninit(drwav* pWav);
DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
#ifndef DR_WAV_NO_CONVERSION_API
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
#endif
#ifndef DR_WAV_NO_STDIO
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
#endif
DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
#ifndef DR_WAV_NO_CONVERSION_API
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAl...
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocati...
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAl...
#ifndef DR_WAV_NO_STDIO
DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
#endif
DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
#endif
DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
#ifdef __cplusplus
}
#endif
#endif
/* dr_wav_h end */
#endif /* MA_NO_WAV */
#if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING)
/* dr_flac_h begin */
#ifndef dr_flac_h
#define dr_flac_h
#ifdef __cplusplus
extern "C" {
#endif
#define DRFLAC_STRINGIFY(x) #x
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 20
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h>
typedef signed char drflac_int8;
typedef unsigned char drflac_uint8;
typedef signed short drflac_int16;
typedef unsigned short drflac_uint16;
typedef signed int drflac_int32;
typedef unsigned int drflac_uint32;
#if defined(_MSC_VER)
typedef signed __int64 drflac_int64;
typedef unsigned __int64 drflac_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 drflac_int64;
typedef unsigned long long drflac_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 drflac_uint64 drflac_uintptr;
#else
typedef drflac_uint32 drflac_uintptr;
#endif
typedef drflac_uint8 drflac_bool8;
typedef drflac_uint32 drflac_bool32;
#define DRFLAC_TRUE 1
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
const void* pRawData;
drflac_uint32 rawDataSize;
union
{
drflac_streaminfo streaminfo;
struct
{
int unused;
} padding;
struct
{
drflac_uint32 id;
const void* pData;
drflac_uint32 dataSize;
} application;
struct
{
drflac_uint32 seekpointCount;
const drflac_seekpoint* pSeekpoints;
} seektable;
struct
{
drflac_uint32 vendorLength;
const char* vendor;
drflac_uint32 commentCount;
const void* pComments;
} vorbis_comment;
struct
{
char catalog[128];
drflac_uint64 leadInSampleCount;
drflac_bool32 isCD;
drflac_uint8 trackCount;
const void* pTrackData;
} cuesheet;
struct
{
drflac_uint32 type;
drflac_uint32 mimeLength;
const char* mime;
drflac_uint32 descriptionLength;
const char* description;
drflac_uint32 width;
drflac_uint32 height;
drflac_uint32 colorDepth;
drflac_uint32 indexColorCount;
drflac_uint32 pictureDataSize;
const drflac_uint8* pPictureData;
} picture;
} data;
} drflac_metadata;
typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
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);
} drflac_allocation_callbacks;
typedef struct
{
const drflac_uint8* data;
size_t dataSize;
size_t currentReadPos;
} drflac__memory_stream;
typedef struct
{
drflac_read_proc onRead;
drflac_seek_proc onSeek;
void* pUserData;
size_t unalignedByteCount;
drflac_cache_t unalignedCache;
drflac_uint32 nextL2Line;
drflac_uint32 consumedBits;
drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
drflac_cache_t cache;
drflac_uint16 crc16;
drflac_cache_t crc16Cache;
drflac_uint32 crc16CacheIgnoredBytes;
} drflac_bs;
typedef struct
{
drflac_uint8 subframeType;
drflac_uint8 wastedBitsPerSample;
drflac_uint8 lpcOrder;
drflac_int32* pSamplesS32;
} drflac_subframe;
typedef struct
{
drflac_uint64 pcmFrameNumber;
drflac_uint32 flacFrameNumber;
drflac_uint32 sampleRate;
drflac_uint16 blockSizeInPCMFrames;
drflac_uint8 channelAssignment;
drflac_uint8 bitsPerSample;
drflac_uint8 crc8;
} drflac_frame_header;
typedef struct
{
drflac_frame_header header;
drflac_uint32 pcmFramesRemaining;
drflac_subframe subframes[8];
} drflac_frame;
typedef struct
{
drflac_meta_proc onMeta;
void* pUserDataMD;
drflac_allocation_callbacks allocationCallbacks;
drflac_uint32 sampleRate;
drflac_uint8 channels;
drflac_uint8 bitsPerSample;
drflac_uint16 maxBlockSizeInPCMFrames;
drflac_uint64 totalPCMFrameCount;
drflac_container container;
drflac_uint32 seekpointCount;
drflac_frame currentFLACFrame;
drflac_uint64 currentPCMFrame;
drflac_uint64 firstFLACFramePosInBytes;
drflac__memory_stream memoryStream;
drflac_int32* pDecodedSamples;
drflac_seekpoint* pSeekpoints;
void* _oggbs;
drflac_bool32 _noSeekTableSeek : 1;
drflac_bool32 _noBinarySearchSeek : 1;
drflac_bool32 _noBruteForceSeek : 1;
drflac_bs bs;
drflac_uint8 pExtraData[1];
} drflac;
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API void drflac_close(drflac* pFlac);
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut);
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut);
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut);
DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex);
#ifndef DR_FLAC_NO_STDIO
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
#endif
DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pA...
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pA...
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocati...
#ifndef DR_FLAC_NO_STDIO
DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
#endif
DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks);
typedef struct
{
drflac_uint32 countRemaining;
const char* pRunningData;
} drflac_vorbis_comment_iterator;
DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments);
DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut);
typedef struct
{
drflac_uint32 countRemaining;
const char* pRunningData;
} drflac_cuesheet_track_iterator;
#pragma pack(4)
typedef struct
{
drflac_uint64 offset;
drflac_uint8 index;
drflac_uint8 reserved[3];
} drflac_cuesheet_track_index;
#pragma pack()
typedef struct
{
drflac_uint64 offset;
drflac_uint8 trackNumber;
char ISRC[12];
drflac_bool8 isAudio;
drflac_bool8 preEmphasis;
drflac_uint8 indexCount;
const drflac_cuesheet_track_index* pIndexPoints;
} drflac_cuesheet_track;
DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData);
DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack);
#ifdef __cplusplus
}
#endif
#endif
/* dr_flac_h end */
#endif /* MA_NO_FLAC */
#if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING)
/* dr_mp3_h begin */
#ifndef dr_mp3_h
#define dr_mp3_h
#ifdef __cplusplus
extern "C" {
#endif
#define DRMP3_STRINGIFY(x) #x
#define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x)
#define DRMP3_VERSION_MAJOR 0
#define DRMP3_VERSION_MINOR 6
#define DRMP3_VERSION_REVISION 17
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
#include <stddef.h>
typedef signed char drmp3_int8;
typedef unsigned char drmp3_uint8;
typedef signed short drmp3_int16;
typedef unsigned short drmp3_uint16;
typedef signed int drmp3_int32;
typedef unsigned int drmp3_uint32;
#if defined(_MSC_VER)
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#define DRMP3_CONNECTION_REFUSED -48
#define DRMP3_NO_HOST -49
#define DRMP3_IN_PROGRESS -50
#define DRMP3_CANCELLED -51
#define DRMP3_MEMORY_ALREADY_MAPPED -52
#define DRMP3_AT_END -53
#define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
#define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
#ifdef _MSC_VER
#define DRMP3_INLINE __forceinline
#elif defined(__GNUC__)
#if defined(__STRICT_ANSI__)
#define DRMP3_INLINE __inline__ __attribute__((always_inline))
#else
#define DRMP3_INLINE inline __attribute__((always_inline))
#endif
#else
#define DRMP3_INLINE
#endif
DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
DRMP3_API const char* drmp3_version_string(void);
typedef struct
{
int frame_bytes, channels, hz, layer, bitrate_kbps;
} drmp3dec_frame_info;
typedef struct
{
float mdct_overlap[2][9*32], qmf_state[15*2*32];
int reserv, free_format_bytes;
drmp3_uint8 header[4], reserv_buf[511];
} drmp3dec;
DRMP3_API void drmp3dec_init(drmp3dec *dec);
DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info);
DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples);
#ifndef DRMP3_DEFAULT_CHANNELS
#define DRMP3_DEFAULT_CHANNELS 2
#endif
#ifndef DRMP3_DEFAULT_SAMPLE_RATE
#define DRMP3_DEFAULT_SAMPLE_RATE 44100
#endif
typedef enum
{
drmp3_seek_origin_start,
drmp3_seek_origin_current
} drmp3_seek_origin;
typedef struct
{
drmp3_uint64 seekPosInBytes;
drmp3_uint64 pcmFrameIndex;
drmp3_uint16 mp3FramesToDiscard;
drmp3_uint16 pcmFramesToDiscard;
} drmp3_seek_point;
typedef size_t (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin);
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);
} drmp3_allocation_callbacks;
typedef struct
{
drmp3_uint32 channels;
drmp3_uint32 sampleRate;
} drmp3_config;
typedef struct
{
drmp3dec decoder;
drmp3dec_frame_info frameInfo;
drmp3_uint32 channels;
drmp3_uint32 sampleRate;
drmp3_read_proc onRead;
drmp3_seek_proc onSeek;
void* pUserData;
drmp3_allocation_callbacks allocationCallbacks;
drmp3_uint32 mp3FrameChannels;
drmp3_uint32 mp3FrameSampleRate;
drmp3_uint32 pcmFramesConsumedInMP3Frame;
drmp3_uint32 pcmFramesRemainingInMP3Frame;
drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME];
drmp3_uint64 currentPCMFrame;
drmp3_uint64 streamCursor;
drmp3_seek_point* pSeekPoints;
drmp3_uint32 seekPointCount;
size_t dataSize;
size_t dataCapacity;
size_t dataConsumed;
drmp3_uint8* pData;
drmp3_bool32 atEnd : 1;
struct
{
const drmp3_uint8* pData;
size_t dataSize;
size_t currentReadPos;
} memory;
} drmp3;
DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks);
#ifndef DR_MP3_NO_STDIO
DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
#endif
DRMP3_API void drmp3_uninit(drmp3* pMP3);
DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut);
DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut);
DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex);
DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3);
DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3);
DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount);
DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints);
DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints);
DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
#ifndef DR_MP3_NO_STDIO
DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
#endif
DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks);
DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks);
#ifdef __cplusplus
}
#endif
#endif
/* dr_mp3_h end */
#endif /* MA_NO_MP3 */
/**************************************************************************************************************************************************************
Decoding
**************************************************************************************************************************************************************/
#ifndef MA_NO_DECODING
static size_t ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
{
size_t bytesRead;
MA_ASSERT(pDecoder != NULL);
MA_ASSERT(pBufferOut != NULL);
bytesRead = pDecoder->onRead(pDecoder, pBufferOut, bytesToRead);
pDecoder->readPointerInBytes += bytesRead;
return bytesRead;
}
static ma_bool32 ma_decoder_seek_bytes(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin)
{
ma_bool32 wasSuccessful;
MA_ASSERT(pDecoder != NULL);
wasSuccessful = pDecoder->onSeek(pDecoder, byteOffset, origin);
if (wasSuccessful) {
if (origin == ma_seek_origin_start) {
pDecoder->readPointerInBytes = (ma_uint64)byteOffset;
} else {
pDecoder->readPointerInBytes += byteOffset;
}
}
return wasSuccessful;
}
MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate)
{
ma_decoder_config config;
MA_ZERO_OBJECT(&config);
config.format = outputFormat;
config.channels = ma_min(outputChannels, ma_countof(config.channelMap));
config.sampleRate = outputSampleRate;
config.resampling.algorithm = ma_resample_algorithm_linear;
config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
config.resampling.speex.quality = 3;
/* Note that we are intentionally leaving the channel map empty here which will cause the default channel map to be used. */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#ifdef dr_wav_h
#define MA_HAS_WAV
static size_t ma_decoder_internal_on_read__wav(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
ma_decoder* pDecoder = (ma_decoder*)pUserData;
MA_ASSERT(pDecoder != NULL);
return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
}
static drwav_bool32 ma_decoder_internal_on_seek__wav(void* pUserData, int offset, drwav_seek_origin origin)
{
ma_decoder* pDecoder = (ma_decoder*)pUserData;
MA_ASSERT(pDecoder != NULL);
return ma_decoder_seek_bytes(pDecoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
}
static ma_uint64 ma_decoder_internal_on_read_pcm_frames__wav(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
drwav* pWav;
MA_ASSERT(pDecoder != NULL);
MA_ASSERT(pFramesOut != NULL);
pWav = (drwav*)pDecoder->pInternalDecoder;
MA_ASSERT(pWav != NULL);
switch (pDecoder->internalFormat) {
case ma_format_s16: return drwav_read_pcm_frames_s16(pWav, frameCount, (drwav_int16*)pFramesOut);
case ma_format_s32: return drwav_read_pcm_frames_s32(pWav, frameCount, (drwav_int32*)pFramesOut);
case ma_format_f32: return drwav_read_pcm_frames_f32(pWav, frameCount, (float*)pFramesOut);
default: break;
}
/* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */
MA_ASSERT(MA_FALSE);
return 0;
}
static ma_result ma_decoder_internal_on_seek_to_pcm_frame__wav(ma_decoder* pDecoder, ma_uint64 frameIndex)
{
drwav* pWav;
drwav_bool32 result;
pWav = (drwav*)pDecoder->pInternalDecoder;
MA_ASSERT(pWav != NULL);
result = drwav_seek_to_pcm_frame(pWav, frameIndex);
if (result) {
return MA_SUCCESS;
} else {
return MA_ERROR;
}
}
static ma_result ma_decoder_internal_on_uninit__wav(ma_decoder* pDecoder)
{
drwav_uninit((drwav*)pDecoder->pInternalDecoder);
ma__free_from_callbacks(pDecoder->pInternalDecoder, &pDecoder->allocationCallbacks);
return MA_SUCCESS;
}
static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__wav(ma_decoder* pDecoder)
{
return ((drwav*)pDecoder->pInternalDecoder)->totalPCMFrameCount;
}
static ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
drwav* pWav;
drwav_allocation_callbacks allocationCallbacks;
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDecoder != NULL);
pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pDecoder->allocationCallbacks);
if (pWav == NULL) {
return MA_OUT_OF_MEMORY;
}
allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc;
allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree;
/* Try opening the decoder first. */
if (!drwav_init(pWav, ma_decoder_internal_on_read__wav, ma_decoder_internal_on_seek__wav, pDecoder, &allocationCallbacks)) {
ma__free_from_callbacks(pWav, &pDecoder->allocationCallbacks);
return MA_ERROR;
}
/* If we get here it means we successfully initialized the WAV decoder. We can now initialize the rest of the ma_decoder. */
pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__wav;
pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__wav;
pDecoder->onUninit = ma_decoder_internal_on_uninit__wav;
pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__wav;
pDecoder->pInternalDecoder = pWav;
/* Try to be as optimal as possible for the internal format. If miniaudio does not support a format we will fall back to f32. */
pDecoder->internalFormat = ma_format_unknown;
switch (pWav->translatedFormatTag) {
case DR_WAVE_FORMAT_PCM:
{
if (pWav->bitsPerSample == 8) {
pDecoder->internalFormat = ma_format_s16;
} else if (pWav->bitsPerSample == 16) {
pDecoder->internalFormat = ma_format_s16;
} else if (pWav->bitsPerSample == 32) {
pDecoder->internalFormat = ma_format_s32;
}
} break;
case DR_WAVE_FORMAT_IEEE_FLOAT:
{
if (pWav->bitsPerSample == 32) {
pDecoder->internalFormat = ma_format_f32;
}
} break;
case DR_WAVE_FORMAT_ALAW:
case DR_WAVE_FORMAT_MULAW:
case DR_WAVE_FORMAT_ADPCM:
case DR_WAVE_FORMAT_DVI_ADPCM:
{
pDecoder->internalFormat = ma_format_s16;
} break;
}
if (pDecoder->internalFormat == ma_format_unknown) {
pDecoder->internalFormat = ma_format_f32;
}
pDecoder->internalChannels = pWav->channels;
pDecoder->internalSampleRate = pWav->sampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDecoder->internalChannels, pDecoder->internalChannelMap);
return MA_SUCCESS;
}
#endif /* dr_wav_h */
/* FLAC */
#ifdef dr_flac_h
#define MA_HAS_FLAC
static size_t ma_decoder_internal_on_read__flac(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
ma_decoder* pDecoder = (ma_decoder*)pUserData;
MA_ASSERT(pDecoder != NULL);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
static drflac_bool32 ma_decoder_internal_on_seek__flac(void* pUserData, int offset, drflac_seek_origin origin)
{
ma_decoder* pDecoder = (ma_decoder*)pUserData;
MA_ASSERT(pDecoder != NULL);
return ma_decoder_seek_bytes(pDecoder, offset, (origin == drflac_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
}
static ma_uint64 ma_decoder_internal_on_read_pcm_frames__flac(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
drflac* pFlac;
MA_ASSERT(pDecoder != NULL);
MA_ASSERT(pFramesOut != NULL);
pFlac = (drflac*)pDecoder->pInternalDecoder;
MA_ASSERT(pFlac != NULL);
switch (pDecoder->internalFormat) {
case ma_format_s16: return drflac_read_pcm_frames_s16(pFlac, frameCount, (drflac_int16*)pFramesOut);
case ma_format_s32: return drflac_read_pcm_frames_s32(pFlac, frameCount, (drflac_int32*)pFramesOut);
case ma_format_f32: return drflac_read_pcm_frames_f32(pFlac, frameCount, (float*)pFramesOut);
default: break;
}
/* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */
MA_ASSERT(MA_FALSE);
return 0;
}
static ma_result ma_decoder_internal_on_seek_to_pcm_frame__flac(ma_decoder* pDecoder, ma_uint64 frameIndex)
{
drflac* pFlac;
drflac_bool32 result;
pFlac = (drflac*)pDecoder->pInternalDecoder;
MA_ASSERT(pFlac != NULL);
result = drflac_seek_to_pcm_frame(pFlac, frameIndex);
if (result) {
return MA_SUCCESS;
} else {
return MA_ERROR;
}
}
static ma_result ma_decoder_internal_on_uninit__flac(ma_decoder* pDecoder)
{
drflac_close((drflac*)pDecoder->pInternalDecoder);
return MA_SUCCESS;
}
static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__flac(ma_decoder* pDecoder)
{
return ((drflac*)pDecoder->pInternalDecoder)->totalPCMFrameCount;
}
static ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
drflac* pFlac;
drflac_allocation_callbacks allocationCallbacks;
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDecoder != NULL);
allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc;
allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree;
/* Try opening the decoder first. */
pFlac = drflac_open(ma_decoder_internal_on_read__flac, ma_decoder_internal_on_seek__flac, pDecoder, &allocationCallbacks);
if (pFlac == NULL) {
return MA_ERROR;
}
/* If we get here it means we successfully initialized the FLAC decoder. We can now initialize the rest of the ma_decoder. */
pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__flac;
pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__flac;
pDecoder->onUninit = ma_decoder_internal_on_uninit__flac;
pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__flac;
pDecoder->pInternalDecoder = pFlac;
/*
dr_flac supports reading as s32, s16 and f32. Try to do a one-to-one mapping if possible, but fall back to s32 if not. s32 is the "native" FLAC format
since it's the only one that's truly lossless. If the internal bits per sample is <= 16 we will decode to ma_format_s16 to keep it more efficient.
*/
if (pConfig->format == ma_format_unknown) {
if (pFlac->bitsPerSample <= 16) {
pDecoder->internalFormat = ma_format_s16;
} else {
pDecoder->internalFormat = ma_format_s32;
}
} else {
if (pConfig->format == ma_format_s16 || pConfig->format == ma_format_f32) {
pDecoder->internalFormat = pConfig->format;
} else {
pDecoder->internalFormat = ma_format_s32; /* s32 as the baseline to ensure no loss of precision for 24-bit encoded files. */
}
}
pDecoder->internalChannels = pFlac->channels;
pDecoder->internalSampleRate = pFlac->sampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_flac, pDecoder->internalChannels, pDecoder->internalChannelMap);
return MA_SUCCESS;
}
#endif /* dr_flac_h */
/* MP3 */
#ifdef dr_mp3_h
#define MA_HAS_MP3
static size_t ma_decoder_internal_on_read__mp3(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
ma_decoder* pDecoder = (ma_decoder*)pUserData;
MA_ASSERT(pDecoder != NULL);
return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
}
static drmp3_bool32 ma_decoder_internal_on_seek__mp3(void* pUserData, int offset, drmp3_seek_origin origin)
{
ma_decoder* pDecoder = (ma_decoder*)pUserData;
MA_ASSERT(pDecoder != NULL);
return ma_decoder_seek_bytes(pDecoder, offset, (origin == drmp3_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
}
static ma_uint64 ma_decoder_internal_on_read_pcm_frames__mp3(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
drmp3* pMP3;
MA_ASSERT(pDecoder != NULL);
MA_ASSERT(pFramesOut != NULL);
pMP3 = (drmp3*)pDecoder->pInternalDecoder;
MA_ASSERT(pMP3 != NULL);
#if defined(DR_MP3_FLOAT_OUTPUT)
MA_ASSERT(pDecoder->internalFormat == ma_format_f32);
return drmp3_read_pcm_frames_f32(pMP3, frameCount, (float*)pFramesOut);
#else
MA_ASSERT(pDecoder->internalFormat == ma_format_s16);
return drmp3_read_pcm_frames_s16(pMP3, frameCount, (drmp3_int16*)pFramesOut);
#endif
}
static ma_result ma_decoder_internal_on_seek_to_pcm_frame__mp3(ma_decoder* pDecoder, ma_uint64 frameIndex)
{
drmp3* pMP3;
drmp3_bool32 result;
pMP3 = (drmp3*)pDecoder->pInternalDecoder;
MA_ASSERT(pMP3 != NULL);
result = drmp3_seek_to_pcm_frame(pMP3, frameIndex);
if (result) {
return MA_SUCCESS;
} else {
return MA_ERROR;
}
}
static ma_result ma_decoder_internal_on_uninit__mp3(ma_decoder* pDecoder)
{
drmp3_uninit((drmp3*)pDecoder->pInternalDecoder);
ma__free_from_callbacks(pDecoder->pInternalDecoder, &pDecoder->allocationCallbacks);
return MA_SUCCESS;
}
static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__mp3(ma_decoder* pDecoder)
{
return drmp3_get_pcm_frame_count((drmp3*)pDecoder->pInternalDecoder);
}
static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
drmp3* pMP3;
drmp3_allocation_callbacks allocationCallbacks;
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDecoder != NULL);
pMP3 = (drmp3*)ma__malloc_from_callbacks(sizeof(*pMP3), &pDecoder->allocationCallbacks);
if (pMP3 == NULL) {
return MA_OUT_OF_MEMORY;
}
allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc;
allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree;
/*
Try opening the decoder first. We always use whatever dr_mp3 reports for channel count and sample rate. The format is determined by
the presence of DR_MP3_FLOAT_OUTPUT.
*/
if (!drmp3_init(pMP3, ma_decoder_internal_on_read__mp3, ma_decoder_internal_on_seek__mp3, pDecoder, &allocationCallbacks)) {
ma__free_from_callbacks(pMP3, &pDecoder->allocationCallbacks);
return MA_ERROR;
}
/* If we get here it means we successfully initialized the MP3 decoder. We can now initialize the rest of the ma_decoder. */
pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__mp3;
pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__mp3;
pDecoder->onUninit = ma_decoder_internal_on_uninit__mp3;
pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__mp3;
pDecoder->pInternalDecoder = pMP3;
/* Internal format. */
#if defined(DR_MP3_FLOAT_OUTPUT)
pDecoder->internalFormat = ma_format_f32;
#else
pDecoder->internalFormat = ma_format_s16;
#endif
pDecoder->internalChannels = pMP3->channels;
pDecoder->internalSampleRate = pMP3->sampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->internalChannels, pDecoder->internalChannelMap);
return MA_SUCCESS;
}
#endif /* dr_mp3_h */
/* Vorbis */
#ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H
#define MA_HAS_VORBIS
/* The size in bytes of each chunk of data to read from the Vorbis stream. */
#define MA_VORBIS_DATA_CHUNK_SIZE 4096
typedef struct
{
stb_vorbis* pInternalVorbis;
ma_uint8* pData;
size_t dataSize;
size_t dataCapacity;
ma_uint32 framesConsumed; /* The number of frames consumed in ppPacketData. */
ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */
float** ppPacketData;
} ma_vorbis_decoder;
static ma_uint64 ma_vorbis_decoder_read_pcm_frames(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
float* pFramesOutF;
ma_uint64 totalFramesRead;
MA_ASSERT(pVorbis != NULL);
MA_ASSERT(pDecoder != NULL);
pFramesOutF = (float*)pFramesOut;
totalFramesRead = 0;
while (frameCount > 0) {
/* Read from the in-memory buffer first. */
ma_uint32 framesToReadFromCache = (ma_uint32)ma_min(pVorbis->framesRemaining, frameCount); /* Safe cast because pVorbis->framesRemaining is 32-bit. */
if (pFramesOut != NULL) {
ma_uint64 iFrame;
for (iFrame = 0; iFrame < framesToReadFromCache; iFrame += 1) {
ma_uint32 iChannel;
for (iChannel = 0; iChannel < pDecoder->internalChannels; ++iChannel) {
pFramesOutF[iChannel] = pVorbis->ppPacketData[iChannel][pVorbis->framesConsumed+iFrame];
}
pFramesOutF += pDecoder->internalChannels;
}
}
pVorbis->framesConsumed += framesToReadFromCache;
pVorbis->framesRemaining -= framesToReadFromCache;
frameCount -= framesToReadFromCache;
totalFramesRead += framesToReadFromCache;
if (frameCount == 0) {
break;
}
MA_ASSERT(pVorbis->framesRemaining == 0);
/* We've run out of cached frames, so decode the next packet and continue iteration. */
do
{
int samplesRead;
int consumedDataSize;
if (pVorbis->dataSize > INT_MAX) {
break; /* Too big. */
}
samplesRead = 0;
consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->pInternalVorbis, pVorbis->pData, (int)pVorbis->dataSize, NULL, (float***)&pVorbis->ppPacketData, &samplesRead);
if (consumedDataSize != 0) {
size_t leftoverDataSize = (pVorbis->dataSize - (size_t)consumedDataSize);
size_t i;
for (i = 0; i < leftoverDataSize; ++i) {
pVorbis->pData[i] = pVorbis->pData[i + consumedDataSize];
}
pVorbis->dataSize = leftoverDataSize;
pVorbis->framesConsumed = 0;
pVorbis->framesRemaining = samplesRead;
break;
} else {
/* Need more data. If there's any room in the existing buffer allocation fill that first. Otherwise expand. */
size_t bytesRead;
if (pVorbis->dataCapacity == pVorbis->dataSize) {
/* No room. Expand. */
size_t oldCap = pVorbis->dataCapacity;
size_t newCap = pVorbis->dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE;
ma_uint8* pNewData;
pNewData = (ma_uint8*)ma__realloc_from_callbacks(pVorbis->pData, newCap, oldCap, &pDecoder->allocationCallbacks);
if (pNewData == NULL) {
return totalFramesRead; /* Out of memory. */
}
pVorbis->pData = pNewData;
pVorbis->dataCapacity = newCap;
}
/* Fill in a chunk. */
bytesRead = ma_decoder_read_bytes(pDecoder, pVorbis->pData + pVorbis->dataSize, (pVorbis->dataCapacity - pVorbis->dataSize));
if (bytesRead == 0) {
return totalFramesRead; /* Error reading more data. */
}
pVorbis->dataSize += bytesRead;
}
} while (MA_TRUE);
}
return totalFramesRead;
}
static ma_result ma_vorbis_decoder_seek_to_pcm_frame(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, ma_uint64 frameIndex)
{
float buffer[4096];
MA_ASSERT(pVorbis != NULL);
MA_ASSERT(pDecoder != NULL);
/*
This is terribly inefficient because stb_vorbis does not have a good seeking solution with it's push API. Currently this just performs
a full decode right from the start of the stream. Later on I'll need to write a layer that goes through all of the Ogg pages until we
find the one containing the sample we need. Then we know exactly where to seek for stb_vorbis.
TODO: Use seeking logic documented for stb_vorbis_flush_pushdata().
*/
if (!ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start)) {
return MA_ERROR;
}
stb_vorbis_flush_pushdata(pVorbis->pInternalVorbis);
pVorbis->framesConsumed = 0;
pVorbis->framesRemaining = 0;
pVorbis->dataSize = 0;
while (frameIndex > 0) {
ma_uint32 framesRead;
ma_uint32 framesToRead = ma_countof(buffer)/pDecoder->internalChannels;
if (framesToRead > frameIndex) {
framesToRead = (ma_uint32)frameIndex;
}
framesRead = (ma_uint32)ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, buffer, framesToRead);
if (framesRead == 0) {
return MA_ERROR;
}
frameIndex -= framesRead;
}
return MA_SUCCESS;
}
static ma_result ma_decoder_internal_on_seek_to_pcm_frame__vorbis(ma_decoder* pDecoder, ma_uint64 frameIndex)
{
ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
MA_ASSERT(pVorbis != NULL);
return ma_vorbis_decoder_seek_to_pcm_frame(pVorbis, pDecoder, frameIndex);
}
static ma_result ma_decoder_internal_on_uninit__vorbis(ma_decoder* pDecoder)
{
ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
MA_ASSERT(pVorbis != NULL);
stb_vorbis_close(pVorbis->pInternalVorbis);
ma__free_from_callbacks(pVorbis->pData, &pDecoder->allocationCallbacks);
ma__free_from_callbacks(pVorbis, &pDecoder->allocationCallbacks);
return MA_SUCCESS;
}
static ma_uint64 ma_decoder_internal_on_read_pcm_frames__vorbis(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
ma_vorbis_decoder* pVorbis;
MA_ASSERT(pDecoder != NULL);
MA_ASSERT(pFramesOut != NULL);
MA_ASSERT(pDecoder->internalFormat == ma_format_f32);
pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
MA_ASSERT(pVorbis != NULL);
return ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, pFramesOut, frameCount);
}
static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__vorbis(ma_decoder* pDecoder)
{
/* No good way to do this with Vorbis. */
(void)pDecoder;
return 0;
}
static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
stb_vorbis* pInternalVorbis = NULL;
size_t dataSize = 0;
size_t dataCapacity = 0;
ma_uint8* pData = NULL;
stb_vorbis_info vorbisInfo;
size_t vorbisDataSize;
ma_vorbis_decoder* pVorbis;
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDecoder != NULL);
/* We grow the buffer in chunks. */
do
{
/* Allocate memory for a new chunk. */
ma_uint8* pNewData;
size_t bytesRead;
int vorbisError = 0;
int consumedDataSize = 0;
size_t oldCapacity = dataCapacity;
dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE;
pNewData = (ma_uint8*)ma__realloc_from_callbacks(pData, dataCapacity, oldCapacity, &pDecoder->allocationCallbacks);
if (pNewData == NULL) {
ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
return MA_OUT_OF_MEMORY;
}
pData = pNewData;
/* Fill in a chunk. */
bytesRead = ma_decoder_read_bytes(pDecoder, pData + dataSize, (dataCapacity - dataSize));
if (bytesRead == 0) {
return MA_ERROR;
}
dataSize += bytesRead;
if (dataSize > INT_MAX) {
return MA_ERROR; /* Too big. */
}
pInternalVorbis = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL);
if (pInternalVorbis != NULL) {
/*
If we get here it means we were able to open the stb_vorbis decoder. There may be some leftover bytes in our buffer, so
we need to move those bytes down to the front of the buffer since they'll be needed for future decoding.
*/
size_t leftoverDataSize = (dataSize - (size_t)consumedDataSize);
size_t i;
for (i = 0; i < leftoverDataSize; ++i) {
pData[i] = pData[i + consumedDataSize];
}
dataSize = leftoverDataSize;
break; /* Success. */
} else {
if (vorbisError == VORBIS_need_more_data) {
continue;
} else {
return MA_ERROR; /* Failed to open the stb_vorbis decoder. */
}
}
} while (MA_TRUE);
/* If we get here it means we successfully opened the Vorbis decoder. */
vorbisInfo = stb_vorbis_get_info(pInternalVorbis);
/* Don't allow more than MA_MAX_CHANNELS channels. */
if (vorbisInfo.channels > MA_MAX_CHANNELS) {
stb_vorbis_close(pInternalVorbis);
ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
return MA_ERROR; /* Too many channels. */
}
vorbisDataSize = sizeof(ma_vorbis_decoder) + sizeof(float)*vorbisInfo.max_frame_size;
pVorbis = (ma_vorbis_decoder*)ma__malloc_from_callbacks(vorbisDataSize, &pDecoder->allocationCallbacks);
if (pVorbis == NULL) {
stb_vorbis_close(pInternalVorbis);
ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
return MA_OUT_OF_MEMORY;
}
MA_ZERO_MEMORY(pVorbis, vorbisDataSize);
pVorbis->pInternalVorbis = pInternalVorbis;
pVorbis->pData = pData;
pVorbis->dataSize = dataSize;
pVorbis->dataCapacity = dataCapacity;
pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__vorbis;
pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__vorbis;
pDecoder->onUninit = ma_decoder_internal_on_uninit__vorbis;
pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__vorbis;
pDecoder->pInternalDecoder = pVorbis;
/* The internal format is always f32. */
pDecoder->internalFormat = ma_format_f32;
pDecoder->internalChannels = vorbisInfo.channels;
pDecoder->internalSampleRate = vorbisInfo.sample_rate;
ma_get_standard_channel_map(ma_standard_channel_map_vorbis, pDecoder->internalChannels, pDecoder->internalChannelMap);
return MA_SUCCESS;
}
#endif /* STB_VORBIS_INCLUDE_STB_VORBIS_H */
/* Raw */
static ma_uint64 ma_decoder_internal_on_read_pcm_frames__raw(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
ma_uint32 bpf;
ma_uint64 totalFramesRead;
void* pRunningFramesOut;
MA_ASSERT(pDecoder != NULL);
/* For raw decoding we just read directly from the decoder's callbacks. */
bpf = ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
totalFramesRead = 0;
pRunningFramesOut = pFramesOut;
while (totalFramesRead < frameCount) {
ma_uint64 framesReadThisIteration;
ma_uint64 framesToReadThisIteration = (frameCount - totalFramesRead);
if (framesToReadThisIteration > 0x7FFFFFFF/bpf) {
framesToReadThisIteration = 0x7FFFFFFF/bpf;
}
if (pFramesOut != NULL) {
framesReadThisIteration = ma_decoder_read_bytes(pDecoder, pRunningFramesOut, (size_t)framesToReadThisIteration * bpf) / bpf; /* Safe cast to size_t. */
pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIteration * bpf);
} else {
/* We'll first try seeking. If this fails it means the end was reached and we'll to do a read-and-discard slow path to get the exact amount. */
if (ma_decoder_seek_bytes(pDecoder, (int)framesToReadThisIteration, ma_seek_origin_current)) {
framesReadThisIteration = framesToReadThisIteration;
} else {
/* Slow path. Need to fall back to a read-and-discard. This is required so we can get the exact number of remaining. */
ma_uint8 buffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 bufferCap = sizeof(buffer) / bpf;
framesReadThisIteration = 0;
while (framesReadThisIteration < framesToReadThisIteration) {
ma_uint64 framesReadNow;
ma_uint64 framesToReadNow = framesToReadThisIteration - framesReadThisIteration;
if (framesToReadNow > bufferCap) {
framesToReadNow = bufferCap;
}
framesReadNow = ma_decoder_read_bytes(pDecoder, buffer, (size_t)(framesToReadNow * bpf)) / bpf; /* Safe cast. */
framesReadThisIteration += framesReadNow;
if (framesReadNow < framesToReadNow) {
break; /* The end has been reached. */
}
}
}
}
totalFramesRead += framesReadThisIteration;
if (framesReadThisIteration < framesToReadThisIteration) {
break; /* Done. */
}
}
return totalFramesRead;
}
static ma_result ma_decoder_internal_on_seek_to_pcm_frame__raw(ma_decoder* pDecoder, ma_uint64 frameIndex)
{
ma_bool32 result = MA_FALSE;
ma_uint64 totalBytesToSeek;
MA_ASSERT(pDecoder != NULL);
if (pDecoder->onSeek == NULL) {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/* Complex case. Start by doing a seek relative to the start. Then keep looping using offset seeking. */
result = ma_decoder_seek_bytes(pDecoder, 0x7FFFFFFF, ma_seek_origin_start);
if (result == MA_TRUE) {
totalBytesToSeek -= 0x7FFFFFFF;
while (totalBytesToSeek > 0) {
ma_uint64 bytesToSeekThisIteration = totalBytesToSeek;
if (bytesToSeekThisIteration > 0x7FFFFFFF) {
bytesToSeekThisIteration = 0x7FFFFFFF;
}
result = ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_current);
if (result != MA_TRUE) {
break;
}
totalBytesToSeek -= bytesToSeekThisIteration;
}
}
}
if (result) {
return MA_SUCCESS;
} else {
return MA_ERROR;
}
}
static ma_result ma_decoder_internal_on_uninit__raw(ma_decoder* pDecoder)
{
(void)pDecoder;
return MA_SUCCESS;
}
static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__raw(ma_decoder* pDecoder)
{
(void)pDecoder;
return 0;
}
static ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
{
MA_ASSERT(pConfigIn != NULL);
MA_ASSERT(pConfigOut != NULL);
MA_ASSERT(pDecoder != NULL);
pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__raw;
pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__raw;
pDecoder->onUninit = ma_decoder_internal_on_uninit__raw;
pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__raw;
/* Internal format. */
pDecoder->internalFormat = pConfigIn->format;
pDecoder->internalChannels = pConfigIn->channels;
pDecoder->internalSampleRate = pConfigIn->sampleRate;
ma_channel_map_copy(pDecoder->internalChannelMap, pConfigIn->channelMap, pConfigIn->channels);
return MA_SUCCESS;
}
static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
MA_ASSERT(pDecoder != NULL);
if (pConfig != NULL) {
return ma_allocation_callbacks_init_copy(&pDecoder->allocationCallbacks, &pConfig->allocationCallbacks);
} else {
pDecoder->allocationCallbacks = ma_allocation_callbacks_init_default();
return MA_SUCCESS;
}
}
static ma_result ma_decoder__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_uint64 framesRead = ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount);
if (pFramesRead != NULL) {
*pFramesRead = framesRead;
}
if (framesRead < frameCount) {
return MA_AT_END;
}
return MA_SUCCESS;
}
static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
return ma_decoder_seek_to_pcm_frame((ma_decoder*)pDataSource, frameIndex);
}
static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
{
ma_decoder* pDecoder = (ma_decoder*)pDataSource;
*pFormat = pDecoder->outputFormat;
*pChannels = pDecoder->outputChannels;
*pSampleRate = pDecoder->outputSampleRate;
return MA_SUCCESS;
}
static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pLength)
{
ma_decoder* pDecoder = (ma_decoder*)pDataSource;
return ma_decoder_get_cursor_in_pcm_frames(pDecoder, pLength);
}
static ma_result ma_decoder__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
ma_decoder* pDecoder = (ma_decoder*)pDataSource;
*pLength = ma_decoder_get_length_in_pcm_frames(pDecoder);
if (*pLength == 0) {
return MA_NOT_IMPLEMENTED;
}
return MA_SUCCESS;
}
static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
ma_result result;
MA_ASSERT(pConfig != NULL);
if (pDecoder == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pDecoder);
if (onRead == NULL || onSeek == NULL) {
return MA_INVALID_ARGS;
}
pDecoder->ds.onRead = ma_decoder__data_source_on_read;
pDecoder->ds.onSeek = ma_decoder__data_source_on_seek;
pDecoder->ds.onGetDataFormat = ma_decoder__data_source_on_get_data_format;
pDecoder->ds.onGetCursor = ma_decoder__data_source_on_get_cursor;
pDecoder->ds.onGetLength = ma_decoder__data_source_on_get_length;
pDecoder->onRead = onRead;
pDecoder->onSeek = onSeek;
pDecoder->pUserData = pUserData;
result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
ma_result result = MA_SUCCESS;
/* Basic validation in case the internal decoder supports different limits to miniaudio. */
if (pDecoder->internalChannels < MA_MIN_CHANNELS || pDecoder->internalChannels > MA_MAX_CHANNELS) {
result = MA_INVALID_DATA;
}
if (result == MA_SUCCESS) {
result = ma_decoder__init_data_converter(pDecoder, pConfig);
}
/* If we failed post initialization we need to uninitialize the decoder before returning to prevent a memory leak. */
if (result != MA_SUCCESS) {
ma_decoder_uninit(pDecoder);
return result;
}
return result;
}
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)
{
#ifdef MA_HAS_WAV
ma_decoder_config config;
ma_result result;
config = ma_decoder_config_init_copy(pConfig);
result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
if (result != MA_SUCCESS) {
return result;
}
result = ma_decoder_init_wav__internal(&config, pDecoder);
if (result != MA_SUCCESS) {
return result;
}
return ma_decoder__postinit(&config, pDecoder);
#else
(void)onRead;
(void)onSeek;
(void)pUserData;
(void)pConfig;
(void)pDecoder;
return MA_NO_BACKEND;
#endif
}
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)
{
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames)
{
ma_uint64 totalFrameCount;
if (pAvailableFrames == NULL) {
return MA_INVALID_ARGS;
}
*pAvailableFrames = 0;
if (pDecoder == NULL) {
return MA_INVALID_ARGS;
}
totalFrameCount = ma_decoder_get_length_in_pcm_frames(pDecoder);
if (totalFrameCount == 0) {
return MA_NOT_IMPLEMENTED;
}
if (totalFrameCount <= pDecoder->readPointerInPCMFrames) {
*pAvailableFrames = 0;
} else {
*pAvailableFrames = totalFrameCount - pDecoder->readPointerInPCMFrames;
}
return MA_SUCCESS; /* No frames available. */
}
static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
{
ma_uint64 totalFrameCount;
ma_uint64 bpf;
ma_uint64 dataCapInFrames;
void* pPCMFramesOut;
MA_ASSERT(pDecoder != NULL);
totalFrameCount = 0;
bpf = ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels);
/* The frame count is unknown until we try reading. Thus, we just run in a loop. */
dataCapInFrames = 0;
pPCMFramesOut = NULL;
for (;;) {
ma_uint64 frameCountToTryReading;
ma_uint64 framesJustRead;
/* Make room if there's not enough. */
if (totalFrameCount == dataCapInFrames) {
void* pNewPCMFramesOut;
ma_uint64 oldDataCapInFrames = dataCapInFrames;
ma_uint64 newDataCapInFrames = dataCapInFrames*2;
if (newDataCapInFrames == 0) {
newDataCapInFrames = 4096;
}
if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) {
ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
return MA_TOO_BIG;
}
pNewPCMFramesOut = (void*)ma__realloc_from_callbacks(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), (size_t)(oldDataCapInFrames * bpf), &pDecoder->allocationCallbacks);
if (pNewPCMFramesOut == NULL) {
ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
return MA_OUT_OF_MEMORY;
}
dataCapInFrames = newDataCapInFrames;
pPCMFramesOut = pNewPCMFramesOut;
}
frameCountToTryReading = dataCapInFrames - totalFrameCount;
MA_ASSERT(frameCountToTryReading > 0);
framesJustRead = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading);
totalFrameCount += framesJustRead;
if (framesJustRead < frameCountToTryReading) {
break;
}
}
if (pConfigOut != NULL) {
pConfigOut->format = pDecoder->outputFormat;
pConfigOut->channels = pDecoder->outputChannels;
pConfigOut->sampleRate = pDecoder->outputSampleRate;
ma_channel_map_copy(pConfigOut->channelMap, pDecoder->outputChannelMap, pDecoder->outputChannels);
}
if (ppPCMFramesOut != NULL) {
*ppPCMFramesOut = pPCMFramesOut;
} else {
ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
}
if (pFrameCountOut != NULL) {
*pFrameCountOut = totalFrameCount;
}
ma_decoder_uninit(pDecoder);
return MA_SUCCESS;
}
MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
{
ma_result result;
ma_decoder_config config;
ma_decoder decoder;
if (pFrameCountOut != NULL) {
*pFrameCountOut = 0;
}
if (ppPCMFramesOut != NULL) {
*ppPCMFramesOut = NULL;
}
config = ma_decoder_config_init_copy(pConfig);
result = ma_decoder_init_vfs(pVFS, pFilePath, &config, &decoder);
if (result != MA_SUCCESS) {
return result;
}
result = ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
return result;
}
MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
{
return ma_decode_from_vfs(NULL, pFilePath, pConfig, pFrameCountOut, ppPCMFramesOut);
}
MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
{
ma_decoder_config config;
ma_decoder decoder;
ma_result result;
if (pFrameCountOut != NULL) {
*pFrameCountOut = 0;
}
if (ppPCMFramesOut != NULL) {
*ppPCMFramesOut = NULL;
}
if (pData == NULL || dataSize == 0) {
return MA_INVALID_ARGS;
}
config = ma_decoder_config_init_copy(pConfig);
result = ma_decoder_init_memory(pData, dataSize, &config, &decoder);
if (result != MA_SUCCESS) {
return result;
}
return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
}
#endif /* MA_NO_DECODING */
#ifndef MA_NO_ENCODING
#if defined(MA_HAS_WAV)
static size_t ma_encoder__internal_on_write_wav(void* pUserData, const void* pData, size_t bytesToWrite)
{
ma_encoder* pEncoder = (ma_encoder*)pUserData;
MA_ASSERT(pEncoder != NULL);
return pEncoder->onWrite(pEncoder, pData, bytesToWrite);
}
static drwav_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, drwav_seek_origin origin)
{
ma_encoder* pEncoder = (ma_encoder*)pUserData;
MA_ASSERT(pEncoder != NULL);
return pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
}
static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder)
{
drwav_data_format wavFormat;
drwav_allocation_callbacks allocationCallbacks;
drwav* pWav;
MA_ASSERT(pEncoder != NULL);
pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pEncoder->config.allocationCallbacks);
if (pWav == NULL) {
return MA_OUT_OF_MEMORY;
}
wavFormat.container = drwav_container_riff;
wavFormat.channels = pEncoder->config.channels;
wavFormat.sampleRate = pEncoder->config.sampleRate;
wavFormat.bitsPerSample = ma_get_bytes_per_sample(pEncoder->config.format) * 8;
if (pEncoder->config.format == ma_format_f32) {
wavFormat.format = DR_WAVE_FORMAT_IEEE_FLOAT;
} else {
wavFormat.format = DR_WAVE_FORMAT_PCM;
}
allocationCallbacks.pUserData = pEncoder->config.allocationCallbacks.pUserData;
allocationCallbacks.onMalloc = pEncoder->config.allocationCallbacks.onMalloc;
allocationCallbacks.onRealloc = pEncoder->config.allocationCallbacks.onRealloc;
allocationCallbacks.onFree = pEncoder->config.allocationCallbacks.onFree;
if (!drwav_init_write(pWav, &wavFormat, ma_encoder__internal_on_write_wav, ma_encoder__internal_on_seek_wav, pEncoder, &allocationCallbacks)) {
return MA_ERROR;
}
pEncoder->pInternalEncoder = pWav;
return MA_SUCCESS;
}
static void ma_encoder__on_uninit_wav(ma_encoder* pEncoder)
{
drwav* pWav;
MA_ASSERT(pEncoder != NULL);
pWav = (drwav*)pEncoder->pInternalEncoder;
MA_ASSERT(pWav != NULL);
drwav_uninit(pWav);
ma__free_from_callbacks(pWav, &pEncoder->config.allocationCallbacks);
}
static ma_uint64 ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount)
{
drwav* pWav;
MA_ASSERT(pEncoder != NULL);
pWav = (drwav*)pEncoder->pInternalEncoder;
MA_ASSERT(pWav != NULL);
return drwav_write_pcm_frames(pWav, frameCount, pFramesIn);
}
#endif
MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
{
ma_encoder_config config;
MA_ZERO_OBJECT(&config);
config.resourceFormat = resourceFormat;
config.format = format;
config.channels = channels;
config.sampleRate = sampleRate;
return config;
}
MA_API ma_result ma_encoder_preinit(const ma_encoder_config* pConfig, ma_encoder* pEncoder)
{
ma_result result;
if (pEncoder == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pEncoder);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->format == ma_format_unknown || pConfig->channels == 0 || pConfig->sampleRate == 0) {
return MA_INVALID_ARGS;
}
pEncoder->config = *pConfig;
result = ma_allocation_callbacks_init_copy(&pEncoder->config.allocationCallbacks, &pConfig->allocationCallbacks);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, ma_encoder* pEncoder)
{
ma_result result = MA_SUCCESS;
/* This assumes ma_encoder_preinit() has been called prior. */
MA_ASSERT(pEncoder != NULL);
if (onWrite == NULL || onSeek == NULL) {
return MA_INVALID_ARGS;
}
pEncoder->onWrite = onWrite;
pEncoder->onSeek = onSeek;
pEncoder->pUserData = pUserData;
switch (pEncoder->config.resourceFormat)
{
case ma_resource_format_wav:
{
#if defined(MA_HAS_WAV)
pEncoder->onInit = ma_encoder__on_init_wav;
pEncoder->onUninit = ma_encoder__on_uninit_wav;
pEncoder->onWritePCMFrames = ma_encoder__on_write_pcm_frames_wav;
#else
result = MA_NO_BACKEND;
#endif
} break;
default:
{
result = MA_INVALID_ARGS;
} break;
}
/* Getting here means we should have our backend callbacks set up. */
if (result == MA_SUCCESS) {
result = pEncoder->onInit(pEncoder);
if (result != MA_SUCCESS) {
return result;
}
}
return MA_SUCCESS;
}
MA_API size_t ma_encoder__on_write_stdio(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite)
{
return fwrite(pBufferIn, 1, bytesToWrite, (FILE*)pEncoder->pFile);
}
MA_API ma_bool32 ma_encoder__on_seek_stdio(ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin)
{
return fseek((FILE*)pEncoder->pFile, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
}
MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
{
ma_result result;
FILE* pFile;
result = ma_encoder_preinit(pConfig, pEncoder);
if (result != MA_SUCCESS) {
return result;
}
/* Now open the file. If this fails we don't need to uninitialize the encoder. */
result = ma_fopen(&pFile, pFilePath, "wb");
if (pFile == NULL) {
return result;
}
pEncoder->pFile = pFile;
return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder);
}
MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
{
ma_result result;
FILE* pFile;
result = ma_encoder_preinit(pConfig, pEncoder);
if (result != MA_SUCCESS) {
return result;
}
/* Now open the file. If this fails we don't need to uninitialize the encoder. */
result = ma_wfopen(&pFile, pFilePath, L"wb", &pEncoder->config.allocationCallbacks);
if (pFile != NULL) {
return result;
}
pEncoder->pFile = pFile;
return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder);
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#if 0
case 2:
{
drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
} break;
#endif
case 4:
{
drwav__bswap_samples_f32((float*)pSamples, sampleCount);
} break;
case 8:
{
drwav__bswap_samples_f64((double*)pSamples, sampleCount);
} break;
default:
{
DRWAV_ASSERT(DRWAV_FALSE);
} break;
}
}
static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
{
switch (format)
{
case DR_WAVE_FORMAT_PCM:
{
drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
} break;
case DR_WAVE_FORMAT_IEEE_FLOAT:
{
drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
} break;
case DR_WAVE_FORMAT_ALAW:
case DR_WAVE_FORMAT_MULAW:
{
drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
} break;
case DR_WAVE_FORMAT_ADPCM:
case DR_WAVE_FORMAT_DVI_ADPCM:
default:
{
DRWAV_ASSERT(DRWAV_FALSE);
} break;
}
}
static void* drwav__malloc_default(size_t sz, void* pUserData)
{
(void)pUserData;
return DRWAV_MALLOC(sz);
}
static void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
{
(void)pUserData;
return DRWAV_REALLOC(p, sz);
}
static void drwav__free_default(void* p, void* pUserData)
{
(void)pUserData;
DRWAV_FREE(p);
}
static void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onMalloc != NULL) {
return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
}
return NULL;
}
static void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
}
if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
void* p2;
p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
if (p2 == NULL) {
return NULL;
}
if (p != NULL) {
DRWAV_COPY_MEMORY(p2, p, szOld);
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
return p2;
}
return NULL;
}
static void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (p == NULL || pAllocationCallbacks == NULL) {
return;
}
if (pAllocationCallbacks->onFree != NULL) {
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
}
static drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
return *pAllocationCallbacks;
} else {
drwav_allocation_callbacks allocationCallbacks;
allocationCallbacks.pUserData = NULL;
allocationCallbacks.onMalloc = drwav__malloc_default;
allocationCallbacks.onRealloc = drwav__realloc_default;
allocationCallbacks.onFree = drwav__free_default;
return allocationCallbacks;
}
}
static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
{
return
formatTag == DR_WAVE_FORMAT_ADPCM ||
formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
}
static unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
{
return (unsigned int)(chunkSize % 2);
}
static unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
{
return (unsigned int)(chunkSize % 8);
}
static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
{
if (container == drwav_container_riff || container == drwav_container_rf64) {
drwav_uint8 sizeInBytes[4];
if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
return DRWAV_AT_END;
}
if (onRead(pUserData, sizeInBytes, 4) != 4) {
return DRWAV_INVALID_FILE;
}
pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes);
pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
*pRunningBytesReadOut += 8;
} else {
drwav_uint8 sizeInBytes[8];
if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
return DRWAV_AT_END;
}
if (onRead(pUserData, sizeInBytes, 8) != 8) {
return DRWAV_INVALID_FILE;
}
pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24;
pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
*pRunningBytesReadOut += 24;
}
return DRWAV_SUCCESS;
}
static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
{
drwav_uint64 bytesRemainingToSeek = offset;
while (bytesRemainingToSeek > 0) {
if (bytesRemainingToSeek > 0x7FFFFFFF) {
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
bytesRemainingToSeek -= 0x7FFFFFFF;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
*pRunningBytesReadOut += fmtOut->extendedSize;
bytesReadSoFar += fmtOut->extendedSize;
}
if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
*pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
}
if (header.paddingSize > 0) {
if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
*pRunningBytesReadOut += header.paddingSize;
}
return DRWAV_TRUE;
}
static size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
{
size_t bytesRead;
DRWAV_ASSERT(onRead != NULL);
DRWAV_ASSERT(pCursor != NULL);
bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
*pCursor += bytesRead;
return bytesRead;
}
#if 0
static drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
{
DRWAV_ASSERT(onSeek != NULL);
DRWAV_ASSERT(pCursor != NULL);
if (!onSeek(pUserData, offset, origin)) {
return DRWAV_FALSE;
}
if (origin == drwav_seek_origin_start) {
*pCursor = offset;
} else {
*pCursor += offset;
}
return DRWAV_TRUE;
}
#endif
static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
{
if ((pWav->bitsPerSample & 0x7) == 0) {
return (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
} else {
return pWav->fmt.blockAlign;
}
}
DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
{
if (pFMT == NULL) {
return 0;
}
if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
return pFMT->formatTag;
} else {
return drwav__bytes_to_u16(pFMT->subFormat);
}
}
static drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pWav == NULL || onRead == NULL || onSeek == NULL) {
return DRWAV_FALSE;
}
DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
pWav->onRead = onRead;
pWav->onSeek = onSeek;
pWav->pUserData = pReadSeekUserData;
pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
return DRWAV_FALSE;
}
return DRWAV_TRUE;
}
static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
{
drwav_uint64 cursor;
drwav_bool32 sequential;
drwav_uint8 riff[4];
drwav_fmt fmt;
unsigned short translatedFormatTag;
drwav_bool32 foundDataChunk;
drwav_uint64 dataChunkSize = 0;
drwav_uint64 sampleCountFromFactChunk = 0;
drwav_uint64 chunkSize;
cursor = 0;
sequential = (flags & DRWAV_SEQUENTIAL) != 0;
if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
return DRWAV_FALSE;
}
if (drwav__fourcc_equal(riff, "RIFF")) {
pWav->container = drwav_container_riff;
} else if (drwav__fourcc_equal(riff, "riff")) {
int i;
drwav_uint8 riff2[12];
pWav->container = drwav_container_w64;
if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
return DRWAV_FALSE;
}
for (i = 0; i < 12; ++i) {
if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
return DRWAV_FALSE;
}
}
} else if (drwav__fourcc_equal(riff, "RF64")) {
pWav->container = drwav_container_rf64;
} else {
return DRWAV_FALSE;
}
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
drwav_uint8 chunkSizeBytes[4];
drwav_uint8 wave[4];
if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
return DRWAV_FALSE;
}
if (pWav->container == drwav_container_riff) {
if (drwav__bytes_to_u32(chunkSizeBytes) < 36) {
return DRWAV_FALSE;
}
} else {
if (drwav__bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
return DRWAV_FALSE;
}
}
if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
return DRWAV_FALSE;
}
if (!drwav__fourcc_equal(wave, "WAVE")) {
return DRWAV_FALSE;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pWav->dataChunkDataPos = cursor;
}
}
if (!foundDataChunk) {
return DRWAV_FALSE;
}
if (!sequential) {
if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
return DRWAV_FALSE;
}
cursor = pWav->dataChunkDataPos;
}
pWav->fmt = fmt;
pWav->sampleRate = fmt.sampleRate;
pWav->channels = fmt.channels;
pWav->bitsPerSample = fmt.bitsPerSample;
pWav->bytesRemaining = dataChunkSize;
pWav->translatedFormatTag = translatedFormatTag;
pWav->dataChunkDataSize = dataChunkSize;
if (sampleCountFromFactChunk != 0) {
pWav->totalPCMFrameCount = sampleCountFromFactChunk;
} else {
pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav);
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
drwav_uint64 totalBlockHeaderSizeInBytes;
drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
if ((blockCount * fmt.blockAlign) < dataChunkSize) {
blockCount += 1;
}
totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
}
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
drwav_uint64 totalBlockHeaderSizeInBytes;
drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
if ((blockCount * fmt.blockAlign) < dataChunkSize) {
blockCount += 1;
}
totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
pWav->totalPCMFrameCount += blockCount;
}
}
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
if (pWav->channels > 2) {
return DRWAV_FALSE;
}
}
#ifdef DR_WAV_LIBSNDFILE_COMPAT
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels;
}
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
}
#endif
return DRWAV_TRUE;
}
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
return DRWAV_FALSE;
}
return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
}
static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
{
drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
if (chunkSize > 0xFFFFFFFFUL) {
chunkSize = 0xFFFFFFFFUL;
}
return (drwav_uint32)chunkSize;
}
static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
{
if (dataChunkSize <= 0xFFFFFFFFUL) {
return (drwav_uint32)dataChunkSize;
} else {
return 0xFFFFFFFFUL;
}
}
static drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
{
drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize;
}
static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
{
return 24 + dataChunkSize;
}
static drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize)
{
drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
if (chunkSize > 0xFFFFFFFFUL) {
chunkSize = 0xFFFFFFFFUL;
}
return chunkSize;
}
static drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
{
return dataChunkSize;
}
static size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
{
DRWAV_ASSERT(pWav != NULL);
DRWAV_ASSERT(pWav->onWrite != NULL);
return pWav->onWrite(pWav->pUserData, pData, dataSize);
}
static size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
{
DRWAV_ASSERT(pWav != NULL);
DRWAV_ASSERT(pWav->onWrite != NULL);
if (!drwav__is_little_endian()) {
value = drwav__bswap16(value);
}
return drwav__write(pWav, &value, 2);
}
static size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
{
DRWAV_ASSERT(pWav != NULL);
DRWAV_ASSERT(pWav->onWrite != NULL);
if (!drwav__is_little_endian()) {
value = drwav__bswap32(value);
}
return drwav__write(pWav, &value, 4);
}
static size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
{
DRWAV_ASSERT(pWav != NULL);
DRWAV_ASSERT(pWav->onWrite != NULL);
if (!drwav__is_little_endian()) {
value = drwav__bswap64(value);
}
return drwav__write(pWav, &value, 8);
}
static drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pWav == NULL || onWrite == NULL) {
return DRWAV_FALSE;
}
if (!isSequential && onSeek == NULL) {
return DRWAV_FALSE;
}
if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
return DRWAV_FALSE;
}
if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
return DRWAV_FALSE;
}
DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
pWav->onWrite = onWrite;
pWav->onSeek = onSeek;
pWav->pUserData = pUserData;
pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
return DRWAV_FALSE;
}
pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
pWav->fmt.channels = (drwav_uint16)pFormat->channels;
pWav->fmt.sampleRate = pFormat->sampleRate;
pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
pWav->fmt.extendedSize = 0;
pWav->isSequentialWrite = isSequential;
return DRWAV_TRUE;
}
static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
{
size_t runningPos = 0;
drwav_uint64 initialDataChunkSize = 0;
drwav_uint64 chunkSizeFMT;
if (pWav->isSequentialWrite) {
initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
if (pFormat->container == drwav_container_riff) {
if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
return DRWAV_FALSE;
}
}
}
pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
if (pFormat->container == drwav_container_riff) {
drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize;
runningPos += drwav__write(pWav, "RIFF", 4);
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
runningPos += drwav__write(pWav, "WAVE", 4);
} else if (pFormat->container == drwav_container_w64) {
drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize;
runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
} else if (pFormat->container == drwav_container_rf64) {
runningPos += drwav__write(pWav, "RF64", 4);
runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
runningPos += drwav__write(pWav, "WAVE", 4);
}
if (pFormat->container == drwav_container_rf64) {
drwav_uint32 initialds64ChunkSize = 28;
drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize;
runningPos += drwav__write(pWav, "ds64", 4);
runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize);
runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize);
runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize);
runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount);
runningPos += drwav__write_u32ne_to_le(pWav, 0);
}
if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
chunkSizeFMT = 16;
runningPos += drwav__write(pWav, "fmt ", 4);
runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
} else if (pFormat->container == drwav_container_w64) {
chunkSizeFMT = 40;
runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
}
runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
pWav->dataChunkDataPos = runningPos;
if (pFormat->container == drwav_container_riff) {
drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
runningPos += drwav__write(pWav, "data", 4);
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
} else if (pFormat->container == drwav_container_w64) {
drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize;
runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
} else if (pFormat->container == drwav_container_rf64) {
runningPos += drwav__write(pWav, "data", 4);
runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
}
pWav->container = pFormat->container;
pWav->channels = (drwav_uint16)pFormat->channels;
pWav->sampleRate = pFormat->sampleRate;
pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
return DRWAV_TRUE;
}
DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
return DRWAV_FALSE;
}
return drwav_init_write__internal(pWav, pFormat, 0);
}
DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
return DRWAV_FALSE;
}
return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
}
DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pFormat == NULL) {
return DRWAV_FALSE;
}
return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
}
DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
{
drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
drwav_uint64 riffChunkSizeBytes;
drwav_uint64 fileSizeBytes = 0;
if (pFormat->container == drwav_container_riff) {
riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
fileSizeBytes = (8 + riffChunkSizeBytes);
} else if (pFormat->container == drwav_container_w64) {
riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
fileSizeBytes = riffChunkSizeBytes;
} else if (pFormat->container == drwav_container_rf64) {
riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes);
fileSizeBytes = (8 + riffChunkSizeBytes);
}
return fileSizeBytes;
}
#ifndef DR_WAV_NO_STDIO
#include <errno.h>
static drwav_result drwav_result_from_errno(int e)
{
switch (e)
{
case 0: return DRWAV_SUCCESS;
#ifdef EPERM
case EPERM: return DRWAV_INVALID_OPERATION;
#endif
#ifdef ENOENT
case ENOENT: return DRWAV_DOES_NOT_EXIST;
#endif
#ifdef ESRCH
case ESRCH: return DRWAV_DOES_NOT_EXIST;
#endif
#ifdef EINTR
case EINTR: return DRWAV_INTERRUPT;
#endif
#ifdef EIO
case EIO: return DRWAV_IO_ERROR;
#endif
#ifdef ENXIO
case ENXIO: return DRWAV_DOES_NOT_EXIST;
#endif
#ifdef E2BIG
case E2BIG: return DRWAV_INVALID_ARGS;
#endif
#ifdef ENOEXEC
case ENOEXEC: return DRWAV_INVALID_FILE;
#endif
#ifdef EBADF
case EBADF: return DRWAV_INVALID_FILE;
#endif
#ifdef ECHILD
case ECHILD: return DRWAV_ERROR;
#endif
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#endif
#ifdef EKEYREJECTED
case EKEYREJECTED: return DRWAV_ERROR;
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD: return DRWAV_ERROR;
#endif
#ifdef ENOTRECOVERABLE
case ENOTRECOVERABLE: return DRWAV_ERROR;
#endif
#ifdef ERFKILL
case ERFKILL: return DRWAV_ERROR;
#endif
#ifdef EHWPOISON
case EHWPOISON: return DRWAV_ERROR;
#endif
default: return DRWAV_ERROR;
}
}
static drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{
#if _MSC_VER && _MSC_VER >= 1400
errno_t err;
#endif
if (ppFile != NULL) {
*ppFile = NULL;
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return DRWAV_INVALID_ARGS;
}
#if _MSC_VER && _MSC_VER >= 1400
err = fopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drwav_result_from_errno(err);
}
#else
#if defined(_WIN32) || defined(__APPLE__)
*ppFile = fopen(pFilePath, pOpenMode);
#else
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
*ppFile = fopen64(pFilePath, pOpenMode);
#else
*ppFile = fopen(pFilePath, pOpenMode);
#endif
#endif
if (*ppFile == NULL) {
drwav_result result = drwav_result_from_errno(errno);
if (result == DRWAV_SUCCESS) {
result = DRWAV_ERROR;
}
return result;
}
#endif
return DRWAV_SUCCESS;
}
#if defined(_WIN32)
#if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
#define DRWAV_HAS_WFOPEN
#endif
#endif
static drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (ppFile != NULL) {
*ppFile = NULL;
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return DRWAV_INVALID_ARGS;
}
#if defined(DRWAV_HAS_WFOPEN)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drwav_result_from_errno(err);
}
#else
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return drwav_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
DRWAV_ZERO_OBJECT(&mbs);
lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
if (lenMB == (size_t)-1) {
return drwav_result_from_errno(errno);
}
pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
if (pFilePathMB == NULL) {
return DRWAV_OUT_OF_MEMORY;
}
pFilePathTemp = pFilePath;
DRWAV_ZERO_OBJECT(&mbs);
wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
{
size_t i = 0;
for (;;) {
if (pOpenMode[i] == 0) {
pOpenModeMB[i] = '\0';
break;
}
pOpenModeMB[i] = (char)pOpenMode[i];
i += 1;
}
}
*ppFile = fopen(pFilePathMB, pOpenModeMB);
drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
}
if (*ppFile == NULL) {
return DRWAV_ERROR;
}
#endif
return DRWAV_SUCCESS;
}
static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
}
static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
{
return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
}
static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
{
return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
}
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
}
static drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav_bool32 result;
result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (result != DRWAV_TRUE) {
fclose(pFile);
return result;
}
result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
if (result != DRWAV_TRUE) {
fclose(pFile);
return result;
}
return DRWAV_TRUE;
}
DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
{
FILE* pFile;
if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
{
FILE* pFile;
if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
}
static drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav_bool32 result;
result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (result != DRWAV_TRUE) {
fclose(pFile);
return result;
}
result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
if (result != DRWAV_TRUE) {
fclose(pFile);
return result;
}
return DRWAV_TRUE;
}
static drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
{
FILE* pFile;
if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
}
static drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
{
FILE* pFile;
if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pFormat == NULL) {
return DRWAV_FALSE;
}
return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pFormat == NULL) {
return DRWAV_FALSE;
}
return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
}
#endif
static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
drwav* pWav = (drwav*)pUserData;
size_t bytesRemaining;
DRWAV_ASSERT(pWav != NULL);
DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
if (bytesToRead > bytesRemaining) {
bytesToRead = bytesRemaining;
}
if (bytesToRead > 0) {
DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
pWav->memoryStream.currentReadPos += bytesToRead;
}
return bytesToRead;
}
static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
{
drwav* pWav = (drwav*)pUserData;
DRWAV_ASSERT(pWav != NULL);
if (origin == drwav_seek_origin_current) {
if (offset > 0) {
if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
return DRWAV_FALSE;
}
} else {
if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
return DRWAV_FALSE;
}
}
pWav->memoryStream.currentReadPos += offset;
} else {
if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
pWav->memoryStream.currentReadPos = offset;
} else {
return DRWAV_FALSE;
}
}
return DRWAV_TRUE;
}
static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
{
drwav* pWav = (drwav*)pUserData;
size_t bytesRemaining;
DRWAV_ASSERT(pWav != NULL);
DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
if (bytesRemaining < bytesToWrite) {
void* pNewData;
size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
}
pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
if (pNewData == NULL) {
return 0;
}
*pWav->memoryStreamWrite.ppData = pNewData;
pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
}
DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
}
*pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
return bytesToWrite;
}
static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
{
drwav* pWav = (drwav*)pUserData;
DRWAV_ASSERT(pWav != NULL);
if (origin == drwav_seek_origin_current) {
if (offset > 0) {
if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos);
}
} else {
if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
offset = -(int)pWav->memoryStreamWrite.currentWritePos;
}
}
pWav->memoryStreamWrite.currentWritePos += offset;
} else {
if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
pWav->memoryStreamWrite.currentWritePos = offset;
} else {
pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize;
}
}
return DRWAV_TRUE;
}
DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (data == NULL || dataSize == 0) {
return DRWAV_FALSE;
}
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
return DRWAV_FALSE;
}
pWav->memoryStream.data = (const drwav_uint8*)data;
pWav->memoryStream.dataSize = dataSize;
pWav->memoryStream.currentReadPos = 0;
return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
}
static drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (ppData == NULL || pDataSize == NULL) {
return DRWAV_FALSE;
}
*ppData = NULL;
*pDataSize = 0;
if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
return DRWAV_FALSE;
}
pWav->memoryStreamWrite.ppData = ppData;
pWav->memoryStreamWrite.pDataSize = pDataSize;
pWav->memoryStreamWrite.dataSize = 0;
pWav->memoryStreamWrite.dataCapacity = 0;
pWav->memoryStreamWrite.currentWritePos = 0;
return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
}
DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
}
DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pFormat == NULL) {
return DRWAV_FALSE;
}
return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
}
DRWAV_API drwav_result drwav_uninit(drwav* pWav)
{
drwav_result result = DRWAV_SUCCESS;
if (pWav == NULL) {
return DRWAV_INVALID_ARGS;
}
if (pWav->onWrite != NULL) {
drwav_uint32 paddingSize = 0;
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
} else {
paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
}
if (paddingSize > 0) {
drwav_uint64 paddingData = 0;
drwav__write(pWav, &paddingData, paddingSize);
}
if (pWav->onSeek && !pWav->isSequentialWrite) {
if (pWav->container == drwav_container_riff) {
if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize);
drwav__write_u32ne_to_le(pWav, riffChunkSize);
}
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) {
drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
drwav__write_u32ne_to_le(pWav, dataChunkSize);
}
} else if (pWav->container == drwav_container_w64) {
if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, riffChunkSize);
}
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) {
drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, dataChunkSize);
}
} else if (pWav->container == drwav_container_rf64) {
int ds64BodyPos = 12 + 8;
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, riffChunkSize);
}
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, dataChunkSize);
}
}
}
if (pWav->isSequentialWrite) {
if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
result = DRWAV_INVALID_FILE;
}
}
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
for (i = 0; i < sampleCount; ++i) {
unsigned int s0 = pIn[i*3 + 0];
unsigned int s1 = pIn[i*3 + 1];
unsigned int s2 = pIn[i*3 + 2];
drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
*pOut++ = sample32;
}
}
DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
{
size_t i;
if (pOut == NULL || pIn == NULL) {
return;
}
for (i = 0; i < sampleCount; ++i) {
*pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
}
}
DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
{
size_t i;
if (pOut == NULL || pIn == NULL) {
return;
}
for (i = 0; i < sampleCount; ++i) {
*pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
}
}
DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
{
size_t i;
if (pOut == NULL || pIn == NULL) {
return;
}
for (i = 0; i < sampleCount; ++i) {
*pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
}
}
DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
{
size_t i;
if (pOut == NULL || pIn == NULL) {
return;
}
for (i= 0; i < sampleCount; ++i) {
*pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
}
}
static drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
{
drwav_uint64 sampleDataSize;
drwav_int16* pSampleData;
drwav_uint64 framesRead;
DRWAV_ASSERT(pWav != NULL);
sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
if (sampleDataSize > DRWAV_SIZE_MAX) {
drwav_uninit(pWav);
return NULL;
}
pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
if (pSampleData == NULL) {
drwav_uninit(pWav);
return NULL;
}
framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
if (framesRead != pWav->totalPCMFrameCount) {
drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
drwav_uninit(pWav);
return NULL;
}
drwav_uninit(pWav);
if (sampleRate) {
*sampleRate = pWav->sampleRate;
}
if (channels) {
*channels = pWav->channels;
}
if (totalFrameCount) {
*totalFrameCount = pWav->totalPCMFrameCount;
}
return pSampleData;
}
static float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
{
drwav_uint64 sampleDataSize;
float* pSampleData;
drwav_uint64 framesRead;
DRWAV_ASSERT(pWav != NULL);
sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
if (sampleDataSize > DRWAV_SIZE_MAX) {
drwav_uninit(pWav);
return NULL;
}
pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
if (pSampleData == NULL) {
drwav_uninit(pWav);
return NULL;
}
framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
if (framesRead != pWav->totalPCMFrameCount) {
drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
drwav_uninit(pWav);
return NULL;
}
drwav_uninit(pWav);
if (sampleRate) {
*sampleRate = pWav->sampleRate;
}
if (channels) {
*channels = pWav->channels;
}
if (totalFrameCount) {
*totalFrameCount = pWav->totalPCMFrameCount;
}
return pSampleData;
}
static drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
{
drwav_uint64 sampleDataSize;
drwav_int32* pSampleData;
drwav_uint64 framesRead;
DRWAV_ASSERT(pWav != NULL);
sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
if (sampleDataSize > DRWAV_SIZE_MAX) {
drwav_uninit(pWav);
return NULL;
}
pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
if (pSampleData == NULL) {
drwav_uninit(pWav);
return NULL;
}
framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
if (framesRead != pWav->totalPCMFrameCount) {
drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
drwav_uninit(pWav);
return NULL;
}
drwav_uninit(pWav);
if (sampleRate) {
*sampleRate = pWav->sampleRate;
}
if (channels) {
*channels = pWav->channels;
}
if (totalFrameCount) {
*totalFrameCount = pWav->totalPCMFrameCount;
}
return pSampleData;
}
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAl...
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocati...
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAl...
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
#ifndef DR_WAV_NO_STDIO
DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (channelsOut) {
*channelsOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (channelsOut) {
*channelsOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (channelsOut) {
*channelsOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
#endif
DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
{
drwav wav;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalFrameCountOut) {
*totalFrameCountOut = 0;
}
if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
return NULL;
}
return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
}
#endif
DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
drwav__free_from_callbacks(p, pAllocationCallbacks);
} else {
drwav__free_default(p, NULL);
}
}
DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
{
return drwav__bytes_to_u16(data);
}
DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
{
return drwav__bytes_to_s16(data);
}
DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
{
return drwav__bytes_to_u32(data);
}
DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
{
return drwav__bytes_to_s32(data);
}
DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
{
return drwav__bytes_to_u64(data);
}
DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
{
return drwav__bytes_to_s64(data);
}
DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
{
return drwav__guid_equal(a, b);
}
DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
{
return drwav__fourcc_equal(a, b);
}
#endif
/* dr_wav_c end */
#endif /* DRWAV_IMPLEMENTATION */
#endif /* MA_NO_WAV */
#if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING)
#if !defined(DR_FLAC_IMPLEMENTATION) && !defined(DRFLAC_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
/* dr_flac_c begin */
#ifndef dr_flac_c
#define dr_flac_c
#if defined(__GNUC__)
#pragma GCC diagnostic push
#if __GNUC__ >= 7
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
#endif
#ifdef __linux__
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#ifndef __USE_BSD
#define __USE_BSD
#endif
#include <endian.h>
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
*blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24);
*blockSize = (blockHeader & 0x00FFFFFFUL);
}
static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
{
drflac_uint32 blockHeader;
*blockSize = 0;
if (onRead(pUserData, &blockHeader, 4) != 4) {
return DRFLAC_FALSE;
}
drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
{
drflac_uint32 blockSizes;
drflac_uint64 frameSizes = 0;
drflac_uint64 importantProps;
drflac_uint8 md5[16];
if (onRead(pUserData, &blockSizes, 4) != 4) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, &frameSizes, 6) != 6) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, &importantProps, 8) != 8) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
return DRFLAC_FALSE;
}
blockSizes = drflac__be2host_32(blockSizes);
frameSizes = drflac__be2host_64(frameSizes);
importantProps = drflac__be2host_64(importantProps);
pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16);
pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF);
pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40);
pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 0)) >> 16);
pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44);
pStreamInfo->channels = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1;
pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1;
pStreamInfo->totalPCMFrameCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF)));
DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5));
return DRFLAC_TRUE;
}
static void* drflac__malloc_default(size_t sz, void* pUserData)
{
(void)pUserData;
return DRFLAC_MALLOC(sz);
}
static void* drflac__realloc_default(void* p, size_t sz, void* pUserData)
{
(void)pUserData;
return DRFLAC_REALLOC(p, sz);
}
static void drflac__free_default(void* p, void* pUserData)
{
(void)pUserData;
DRFLAC_FREE(p);
}
static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onMalloc != NULL) {
return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
}
return NULL;
}
static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
}
if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
void* p2;
p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
if (p2 == NULL) {
return NULL;
}
if (p != NULL) {
DRFLAC_COPY_MEMORY(p2, p, szOld);
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
return p2;
}
return NULL;
}
static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (p == NULL || pAllocationCallbacks == NULL) {
return;
}
if (pAllocationCallbacks->onFree != NULL) {
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
}
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektabl...
{
drflac_uint64 runningFilePos = 42;
drflac_uint64 seektablePos = 0;
drflac_uint32 seektableSize = 0;
for (;;) {
drflac_metadata metadata;
drflac_uint8 isLastBlock = 0;
drflac_uint8 blockType;
drflac_uint32 blockSize;
if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
return DRFLAC_FALSE;
}
runningFilePos += 4;
metadata.type = blockType;
metadata.pRawData = NULL;
metadata.rawDataSize = 0;
switch (blockType)
{
case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
{
if (blockSize < 4) {
return DRFLAC_FALSE;
}
if (onMeta) {
void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
metadata.data.application.id = drflac__be2host_32(*(drflac_uint32*)pRawData);
metadata.data.application.pData = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32));
metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32);
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
{
seektablePos = runningFilePos;
seektableSize = blockSize;
if (onMeta) {
drflac_uint32 iSeekpoint;
void* pRawData;
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame);
pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset);
pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount);
}
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
{
if (blockSize < 8) {
return DRFLAC_FALSE;
}
if (onMeta) {
void* pRawData;
const char* pRunningData;
const char* pRunningDataEnd;
drflac_uint32 i;
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
pRunningData = (const char*)pRawData;
pRunningDataEnd = (const char*)pRawData + blockSize;
metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.data.vorbis_comment.pComments = pRunningData;
for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) {
drflac_uint32 commentLength;
if (pRunningDataEnd - pRunningData < 4) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
pRunningData += commentLength;
}
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
{
if (blockSize < 396) {
return DRFLAC_FALSE;
}
if (onMeta) {
void* pRawData;
const char* pRunningData;
const char* pRunningDataEnd;
drflac_uint8 iTrack;
drflac_uint8 iIndex;
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
pRunningData = (const char*)pRawData;
pRunningDataEnd = (const char*)pRawData + blockSize;
DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128;
metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8;
metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259;
metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1;
metadata.data.cuesheet.pTrackData = pRunningData;
for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
drflac_uint8 indexCount;
drflac_uint32 indexPointSize;
if (pRunningDataEnd - pRunningData < 36) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
pRunningData += 35;
indexCount = pRunningData[0]; pRunningData += 1;
indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index);
if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
for (iIndex = 0; iIndex < indexCount; ++iIndex) {
drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData;
pRunningData += sizeof(drflac_cuesheet_track_index);
pTrack->offset = drflac__be2host_64(pTrack->offset);
}
}
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
{
if (blockSize < 32) {
return DRFLAC_FALSE;
}
if (onMeta) {
void* pRawData;
const char* pRunningData;
const char* pRunningDataEnd;
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
pRunningData = (const char*)pRawData;
pRunningDataEnd = (const char*)pRawData + blockSize;
metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength;
metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData;
if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
{
if (onMeta) {
metadata.data.padding.unused = 0;
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
isLastBlock = DRFLAC_TRUE;
} else {
onMeta(pUserDataMD, &metadata);
}
}
} break;
case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
{
if (onMeta) {
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
isLastBlock = DRFLAC_TRUE;
}
}
} break;
default:
{
if (onMeta) {
void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
}
if (onMeta == NULL && blockSize > 0) {
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
isLastBlock = DRFLAC_TRUE;
}
}
runningFilePos += blockSize;
if (isLastBlock) {
break;
}
}
*pSeektablePos = seektablePos;
*pSeektableSize = seektableSize;
*pFirstFramePos = runningFilePos;
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
{
drflac_uint8 isLastBlock;
drflac_uint8 blockType;
drflac_uint32 blockSize;
(void)onSeek;
pInit->container = drflac_container_native;
if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
return DRFLAC_FALSE;
}
if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
if (!relaxed) {
return DRFLAC_FALSE;
} else {
pInit->hasStreamInfoBlock = DRFLAC_FALSE;
pInit->hasMetadataBlocks = DRFLAC_FALSE;
if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) {
return DRFLAC_FALSE;
}
if (pInit->firstFrameHeader.bitsPerSample == 0) {
return DRFLAC_FALSE;
}
pInit->sampleRate = pInit->firstFrameHeader.sampleRate;
pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment);
pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample;
pInit->maxBlockSizeInPCMFrames = 65535;
return DRFLAC_TRUE;
}
} else {
drflac_streaminfo streaminfo;
if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
return DRFLAC_FALSE;
}
pInit->hasStreamInfoBlock = DRFLAC_TRUE;
pInit->sampleRate = streaminfo.sampleRate;
pInit->channels = streaminfo.channels;
pInit->bitsPerSample = streaminfo.bitsPerSample;
pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount;
pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
pInit->hasMetadataBlocks = !isLastBlock;
if (onMeta) {
drflac_metadata metadata;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return DRFLAC_FALSE;
}
pInit->runningFilePos += 4;
if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') {
drflac_uint8 header[6];
drflac_uint8 flags;
drflac_uint32 headerSize;
if (onRead(pUserData, header, 6) != 6) {
return DRFLAC_FALSE;
}
pInit->runningFilePos += 6;
flags = header[1];
DRFLAC_COPY_MEMORY(&headerSize, header+2, 4);
headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize));
if (flags & 0x10) {
headerSize += 10;
}
if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
return DRFLAC_FALSE;
}
pInit->runningFilePos += headerSize;
} else {
break;
}
}
if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
}
#ifndef DR_FLAC_NO_OGG
if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
}
#endif
if (relaxed) {
if (container == drflac_container_native) {
return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
}
#ifndef DR_FLAC_NO_OGG
if (container == drflac_container_ogg) {
return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
}
#endif
}
return DRFLAC_FALSE;
}
static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
{
DRFLAC_ASSERT(pFlac != NULL);
DRFLAC_ASSERT(pInit != NULL);
DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac));
pFlac->bs = pInit->bs;
pFlac->onMeta = pInit->onMeta;
pFlac->pUserDataMD = pInit->pUserDataMD;
pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames;
pFlac->sampleRate = pInit->sampleRate;
pFlac->channels = (drflac_uint8)pInit->channels;
pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample;
pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount;
pFlac->container = pInit->container;
}
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac_init_info init;
drflac_uint32 allocationSize;
drflac_uint32 wholeSIMDVectorCountPerChannel;
drflac_uint32 decodedSamplesAllocationSize;
#ifndef DR_FLAC_NO_OGG
drflac_oggbs oggbs;
#endif
drflac_uint64 firstFramePos;
drflac_uint64 seektablePos;
drflac_uint32 seektableSize;
drflac_allocation_callbacks allocationCallbacks;
drflac* pFlac;
drflac__init_cpu_caps();
if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
return NULL;
}
if (pAllocationCallbacks != NULL) {
allocationCallbacks = *pAllocationCallbacks;
if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) {
return NULL;
}
} else {
allocationCallbacks.pUserData = NULL;
allocationCallbacks.onMalloc = drflac__malloc_default;
allocationCallbacks.onRealloc = drflac__realloc_default;
allocationCallbacks.onFree = drflac__free_default;
}
allocationSize = sizeof(drflac);
if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) {
wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32)));
} else {
wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1;
}
decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels;
allocationSize += decodedSamplesAllocationSize;
allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE;
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg) {
allocationSize += sizeof(drflac_oggbs);
}
DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs));
if (init.container == drflac_container_ogg) {
oggbs.onRead = onRead;
oggbs.onSeek = onSeek;
oggbs.pUserData = pUserData;
oggbs.currentBytePos = init.oggFirstBytePos;
oggbs.firstBytePos = init.oggFirstBytePos;
oggbs.serialNumber = init.oggSerial;
oggbs.bosPageHeader = init.oggBosHeader;
oggbs.bytesRemainingInPage = 0;
}
#endif
firstFramePos = 42;
seektablePos = 0;
seektableSize = 0;
if (init.hasMetadataBlocks) {
drflac_read_proc onReadOverride = onRead;
drflac_seek_proc onSeekOverride = onSeek;
void* pUserDataOverride = pUserData;
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg) {
onReadOverride = drflac__on_read_ogg;
onSeekOverride = drflac__on_seek_ogg;
pUserDataOverride = (void*)&oggbs;
}
#endif
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) {
return NULL;
}
allocationSize += seektableSize;
}
pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
drflac__init_from_info(pFlac, &init);
pFlac->allocationCallbacks = allocationCallbacks;
pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE);
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg) {
drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize);
*pInternalOggbs = oggbs;
pFlac->bs.onRead = drflac__on_read_ogg;
pFlac->bs.onSeek = drflac__on_seek_ogg;
pFlac->bs.pUserData = (void*)pInternalOggbs;
pFlac->_oggbs = (void*)pInternalOggbs;
}
#endif
pFlac->firstFLACFramePosInBytes = firstFramePos;
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg)
{
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
else
#endif
{
if (seektablePos != 0) {
pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints);
pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) {
drflac_uint32 iSeekpoint;
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
}
} else {
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
} else {
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
}
}
if (!init.hasStreamInfoBlock) {
pFlac->currentFLACFrame.header = init.firstFrameHeader;
for (;;) {
drflac_result result = drflac__decode_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
break;
} else {
if (result == DRFLAC_CRC_MISMATCH) {
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
continue;
} else {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
}
}
}
return pFlac;
}
#ifndef DR_FLAC_NO_STDIO
#include <stdio.h>
#include <wchar.h>
#include <errno.h>
static drflac_result drflac_result_from_errno(int e)
{
switch (e)
{
case 0: return DRFLAC_SUCCESS;
#ifdef EPERM
case EPERM: return DRFLAC_INVALID_OPERATION;
#endif
#ifdef ENOENT
case ENOENT: return DRFLAC_DOES_NOT_EXIST;
#endif
#ifdef ESRCH
case ESRCH: return DRFLAC_DOES_NOT_EXIST;
#endif
#ifdef EINTR
case EINTR: return DRFLAC_INTERRUPT;
#endif
#ifdef EIO
case EIO: return DRFLAC_IO_ERROR;
#endif
#ifdef ENXIO
case ENXIO: return DRFLAC_DOES_NOT_EXIST;
#endif
#ifdef E2BIG
case E2BIG: return DRFLAC_INVALID_ARGS;
#endif
#ifdef ENOEXEC
case ENOEXEC: return DRFLAC_INVALID_FILE;
#endif
#ifdef EBADF
case EBADF: return DRFLAC_INVALID_FILE;
#endif
#ifdef ECHILD
case ECHILD: return DRFLAC_ERROR;
#endif
#ifdef EAGAIN
case EAGAIN: return DRFLAC_UNAVAILABLE;
#endif
#ifdef ENOMEM
case ENOMEM: return DRFLAC_OUT_OF_MEMORY;
#endif
#ifdef EACCES
case EACCES: return DRFLAC_ACCESS_DENIED;
#endif
#ifdef EFAULT
case EFAULT: return DRFLAC_BAD_ADDRESS;
#endif
#ifdef ENOTBLK
case ENOTBLK: return DRFLAC_ERROR;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#endif
#ifdef EKEYREJECTED
case EKEYREJECTED: return DRFLAC_ERROR;
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD: return DRFLAC_ERROR;
#endif
#ifdef ENOTRECOVERABLE
case ENOTRECOVERABLE: return DRFLAC_ERROR;
#endif
#ifdef ERFKILL
case ERFKILL: return DRFLAC_ERROR;
#endif
#ifdef EHWPOISON
case EHWPOISON: return DRFLAC_ERROR;
#endif
default: return DRFLAC_ERROR;
}
}
static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{
#if _MSC_VER && _MSC_VER >= 1400
errno_t err;
#endif
if (ppFile != NULL) {
*ppFile = NULL;
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return DRFLAC_INVALID_ARGS;
}
#if _MSC_VER && _MSC_VER >= 1400
err = fopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drflac_result_from_errno(err);
}
#else
#if defined(_WIN32) || defined(__APPLE__)
*ppFile = fopen(pFilePath, pOpenMode);
#else
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
*ppFile = fopen64(pFilePath, pOpenMode);
#else
*ppFile = fopen(pFilePath, pOpenMode);
#endif
#endif
if (*ppFile == NULL) {
drflac_result result = drflac_result_from_errno(errno);
if (result == DRFLAC_SUCCESS) {
result = DRFLAC_ERROR;
}
return result;
}
#endif
return DRFLAC_SUCCESS;
}
#if defined(_WIN32)
#if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
#define DRFLAC_HAS_WFOPEN
#endif
#endif
static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (ppFile != NULL) {
*ppFile = NULL;
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return DRFLAC_INVALID_ARGS;
}
#if defined(DRFLAC_HAS_WFOPEN)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drflac_result_from_errno(err);
}
#else
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return drflac_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
DRFLAC_ZERO_OBJECT(&mbs);
lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
if (lenMB == (size_t)-1) {
return drflac_result_from_errno(errno);
}
pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
if (pFilePathMB == NULL) {
return DRFLAC_OUT_OF_MEMORY;
}
pFilePathTemp = pFilePath;
DRFLAC_ZERO_OBJECT(&mbs);
wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
{
size_t i = 0;
for (;;) {
if (pOpenMode[i] == 0) {
pOpenModeMB[i] = '\0';
break;
}
pOpenModeMB[i] = (char)pOpenMode[i];
i += 1;
}
}
*ppFile = fopen(pFilePathMB, pOpenModeMB);
drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
}
if (*ppFile == NULL) {
return DRFLAC_ERROR;
}
#endif
return DRFLAC_SUCCESS;
}
static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
{
return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
}
static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
{
DRFLAC_ASSERT(offset >= 0);
return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
}
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
FILE* pFile;
if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
return NULL;
}
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return NULL;
}
return pFlac;
}
DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
FILE* pFile;
if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
return NULL;
}
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return NULL;
}
return pFlac;
}
DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
FILE* pFile;
if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
return NULL;
}
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return pFlac;
}
return pFlac;
}
DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
FILE* pFile;
if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
return NULL;
}
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
fclose(pFile);
return pFlac;
}
return pFlac;
}
#endif
static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
{
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
size_t bytesRemaining;
DRFLAC_ASSERT(memoryStream != NULL);
DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos);
bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
if (bytesToRead > bytesRemaining) {
bytesToRead = bytesRemaining;
}
if (bytesToRead > 0) {
DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
memoryStream->currentReadPos += bytesToRead;
}
return bytesToRead;
}
static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
DRFLAC_ASSERT(memoryStream != NULL);
DRFLAC_ASSERT(offset >= 0);
if (offset > (drflac_int64)memoryStream->dataSize) {
return DRFLAC_FALSE;
}
if (origin == drflac_seek_origin_current) {
if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
memoryStream->currentReadPos += offset;
} else {
return DRFLAC_FALSE;
}
} else {
if ((drflac_uint32)offset <= memoryStream->dataSize) {
memoryStream->currentReadPos = offset;
} else {
return DRFLAC_FALSE;
}
}
return DRFLAC_TRUE;
}
DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac__memory_stream memoryStream;
drflac* pFlac;
memoryStream.data = (const drflac_uint8*)pData;
memoryStream.dataSize = dataSize;
memoryStream.currentReadPos = 0;
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
pFlac->memoryStream = memoryStream;
#ifndef DR_FLAC_NO_OGG
if (pFlac->container == drflac_container_ogg)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
oggbs->pUserData = &pFlac->memoryStream;
}
else
#endif
{
pFlac->bs.pUserData = &pFlac->memoryStream;
}
return pFlac;
}
DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac__memory_stream memoryStream;
drflac* pFlac;
memoryStream.data = (const drflac_uint8*)pData;
memoryStream.dataSize = dataSize;
memoryStream.currentReadPos = 0;
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
pFlac->memoryStream = memoryStream;
#ifndef DR_FLAC_NO_OGG
if (pFlac->container == drflac_container_ogg)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
oggbs->pUserData = &pFlac->memoryStream;
}
else
#endif
{
pFlac->bs.pUserData = &pFlac->memoryStream;
}
return pFlac;
}
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API void drflac_close(drflac* pFlac)
{
if (pFlac == NULL) {
return;
}
#ifndef DR_FLAC_NO_STDIO
if (pFlac->bs.onRead == drflac__on_read_stdio) {
fclose((FILE*)pFlac->bs.pUserData);
}
#ifndef DR_FLAC_NO_OGG
if (pFlac->container == drflac_container_ogg) {
drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg);
if (oggbs->onRead == drflac__on_read_stdio) {
fclose((FILE*)oggbs->pUserData);
}
}
#endif
#endif
drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks);
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutpu...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSa...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 right0 = left0 - side0;
drflac_uint32 right1 = left1 - side1;
drflac_uint32 right2 = left2 - side2;
drflac_uint32 right3 = left3 - side3;
pOutputSamples[i*8+0] = (drflac_int32)left0;
pOutputSamples[i*8+1] = (drflac_int32)right0;
pOutputSamples[i*8+2] = (drflac_int32)left1;
pOutputSamples[i*8+3] = (drflac_int32)right1;
pOutputSamples[i*8+4] = (drflac_int32)left2;
pOutputSamples[i*8+5] = (drflac_int32)right2;
pOutputSamples[i*8+6] = (drflac_int32)left3;
pOutputSamples[i*8+7] = (drflac_int32)right3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamp...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return DRFLAC_TRUE;
}
} else {
drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex);
drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining;
if (currentFLACFramePCMFramesConsumed > offsetAbs) {
pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs;
pFlac->currentPCMFrame = pcmFrameIndex;
return DRFLAC_TRUE;
}
}
#ifndef DR_FLAC_NO_OGG
if (pFlac->container == drflac_container_ogg)
{
wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex);
}
else
#endif
{
if (!pFlac->_noSeekTableSeek) {
wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex);
}
#if !defined(DR_FLAC_NO_CRC)
if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) {
wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex);
}
#endif
if (!wasSuccessful && !pFlac->_noBruteForceSeek) {
wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex);
}
}
pFlac->currentPCMFrame = pcmFrameIndex;
return wasSuccessful;
}
}
#if defined(SIZE_MAX)
#define DRFLAC_SIZE_MAX SIZE_MAX
#else
#if defined(DRFLAC_64BIT)
#define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF)
#else
#define DRFLAC_SIZE_MAX 0xFFFFFFFF
#endif
#endif
#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \
static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\
{ \
type* pSampleData = NULL; \
drflac_uint64 totalPCMFrameCount; \
\
DRFLAC_ASSERT(pFlac != NULL); \
\
totalPCMFrameCount = pFlac->totalPCMFrameCount; \
\
if (totalPCMFrameCount == 0) { \
type buffer[4096]; \
drflac_uint64 pcmFramesRead; \
size_t sampleDataBufferSize = sizeof(buffer); \
\
pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \
if (pSampleData == NULL) { \
goto on_error; \
} \
\
while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \
if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \
type* pNewSampleData; \
size_t newSampleDataBufferSize; \
\
newSampleDataBufferSize = sampleDataBufferSize * 2; \
pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \
if (pNewSampleData == NULL) { \
drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \
goto on_error; \
} \
\
sampleDataBufferSize = newSampleDataBufferSize; \
pSampleData = pNewSampleData; \
} \
\
DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \
totalPCMFrameCount += pcmFramesRead; \
} \
\
\
DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \
} else { \
drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \
if (dataSize > DRFLAC_SIZE_MAX) { \
goto on_error; \
} \
\
pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); \
if (pSampleData == NULL) { \
goto on_error; \
} \
\
totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \
} \
\
if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \
if (channelsOut) *channelsOut = pFlac->channels; \
if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \
\
drflac_close(pFlac); \
return pSampleData; \
\
on_error: \
drflac_close(pFlac); \
return NULL; \
}
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_call...
{
drflac* pFlac;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalPCMFrameCountOut) {
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_call...
{
drflac* pFlac;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalPCMFrameCountOut) {
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* ...
{
drflac* pFlac;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalPCMFrameCountOut) {
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
#ifndef DR_FLAC_NO_STDIO
DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_file(filename, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_file(filename, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_file(filename, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
#endif
DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
drflac__free_from_callbacks(p, pAllocationCallbacks);
} else {
drflac__free_default(p, NULL);
}
}
DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments)
{
if (pIter == NULL) {
return;
}
pIter->countRemaining = commentCount;
pIter->pRunningData = (const char*)pComments;
}
DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut)
{
drflac_int32 length;
const char* pComment;
if (pCommentLengthOut) {
*pCommentLengthOut = 0;
}
if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
return NULL;
}
length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData);
pIter->pRunningData += 4;
pComment = pIter->pRunningData;
pIter->pRunningData += length;
pIter->countRemaining -= 1;
if (pCommentLengthOut) {
*pCommentLengthOut = length;
}
return pComment;
}
DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData)
{
if (pIter == NULL) {
return;
}
pIter->countRemaining = trackCount;
pIter->pRunningData = (const char*)pTrackData;
}
DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack)
{
drflac_cuesheet_track cuesheetTrack;
const char* pRunningData;
drflac_uint64 offsetHi;
drflac_uint64 offsetLo;
if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
return DRFLAC_FALSE;
}
pRunningData = pIter->pRunningData;
offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
cuesheetTrack.offset = offsetLo | (offsetHi << 32);
cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1;
DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12;
cuesheetTrack.isAudio = (pRunningData[0] & 0x80) != 0;
cuesheetTrack.preEmphasis = (pRunningData[0] & 0x40) != 0; pRunningData += 14;
cuesheetTrack.indexCount = pRunningData[0]; pRunningData += 1;
cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index);
pIter->pRunningData = pRunningData;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#endif
#ifndef DRMP3_FREE
#define DRMP3_FREE(p) free((p))
#endif
#define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
#define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi)))
#ifndef DRMP3_PI_D
#define DRMP3_PI_D 3.14159265358979323846264
#endif
#define DRMP3_DEFAULT_RESAMPLER_LPF_ORDER 2
static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a)
{
return x*(1-a) + y*a;
}
static DRMP3_INLINE float drmp3_mix_f32_fast(float x, float y, float a)
{
float r0 = (y - x);
float r1 = r0*a;
return x + r1;
}
static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b)
{
for (;;) {
if (b == 0) {
break;
} else {
drmp3_uint32 t = a;
a = b;
b = t % a;
}
}
return a;
}
static DRMP3_INLINE double drmp3_sin(double x)
{
return sin(x);
}
static DRMP3_INLINE double drmp3_exp(double x)
{
return exp(x);
}
static DRMP3_INLINE double drmp3_cos(double x)
{
return drmp3_sin((DRMP3_PI_D*0.5) - x);
}
static void* drmp3__malloc_default(size_t sz, void* pUserData)
{
(void)pUserData;
return DRMP3_MALLOC(sz);
}
static void* drmp3__realloc_default(void* p, size_t sz, void* pUserData)
{
(void)pUserData;
return DRMP3_REALLOC(p, sz);
}
static void drmp3__free_default(void* p, void* pUserData)
{
(void)pUserData;
DRMP3_FREE(p);
}
static void* drmp3__malloc_from_callbacks(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onMalloc != NULL) {
return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
}
return NULL;
}
static void* drmp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
}
if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
void* p2;
p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
if (p2 == NULL) {
return NULL;
}
if (p != NULL) {
DRMP3_COPY_MEMORY(p2, p, szOld);
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
return p2;
}
return NULL;
}
static void drmp3__free_from_callbacks(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (p == NULL || pAllocationCallbacks == NULL) {
return;
}
if (pAllocationCallbacks->onFree != NULL) {
pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
}
}
static drmp3_allocation_callbacks drmp3_copy_allocation_callbacks_or_defaults(const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
return *pAllocationCallbacks;
} else {
drmp3_allocation_callbacks allocationCallbacks;
allocationCallbacks.pUserData = NULL;
allocationCallbacks.onMalloc = drmp3__malloc_default;
allocationCallbacks.onRealloc = drmp3__realloc_default;
allocationCallbacks.onFree = drmp3__free_default;
return allocationCallbacks;
}
}
static size_t drmp3__on_read(drmp3* pMP3, void* pBufferOut, size_t bytesToRead)
{
size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead);
pMP3->streamCursor += bytesRead;
return bytesRead;
}
static drmp3_bool32 drmp3__on_seek(drmp3* pMP3, int offset, drmp3_seek_origin origin)
{
DRMP3_ASSERT(offset >= 0);
if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) {
return DRMP3_FALSE;
}
if (origin == drmp3_seek_origin_start) {
pMP3->streamCursor = (drmp3_uint64)offset;
} else {
pMP3->streamCursor += offset;
}
return DRMP3_TRUE;
}
static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_seek_origin origin)
{
if (offset <= 0x7FFFFFFF) {
return drmp3__on_seek(pMP3, (int)offset, origin);
}
if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) {
return DRMP3_FALSE;
}
offset -= 0x7FFFFFFF;
while (offset > 0) {
if (offset <= 0x7FFFFFFF) {
if (!drmp3__on_seek(pMP3, (int)offset, drmp3_seek_origin_current)) {
return DRMP3_FALSE;
}
offset = 0;
} else {
if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_current)) {
return DRMP3_FALSE;
}
offset -= 0x7FFFFFFF;
}
}
return DRMP3_TRUE;
}
static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
{
drmp3_uint32 pcmFramesRead = 0;
DRMP3_ASSERT(pMP3 != NULL);
DRMP3_ASSERT(pMP3->onRead != NULL);
if (pMP3->atEnd) {
return 0;
}
for (;;) {
drmp3dec_frame_info info;
if (pMP3->dataSize < DRMP3_MIN_DATA_CHUNK_SIZE) {
size_t bytesRead;
if (pMP3->pData != NULL) {
memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
}
pMP3->dataConsumed = 0;
if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) {
drmp3_uint8* pNewData;
size_t newDataCap;
newDataCap = DRMP3_DATA_CHUNK_SIZE;
pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
if (pNewData == NULL) {
return 0;
}
pMP3->pData = pNewData;
pMP3->dataCapacity = newDataCap;
}
bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
if (bytesRead == 0) {
if (pMP3->dataSize == 0) {
pMP3->atEnd = DRMP3_TRUE;
return 0;
}
}
pMP3->dataSize += bytesRead;
}
if (pMP3->dataSize > INT_MAX) {
pMP3->atEnd = DRMP3_TRUE;
return 0;
}
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info);
if (info.frame_bytes > 0) {
pMP3->dataConsumed += (size_t)info.frame_bytes;
pMP3->dataSize -= (size_t)info.frame_bytes;
}
if (pcmFramesRead > 0) {
pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
pMP3->pcmFramesConsumedInMP3Frame = 0;
pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
pMP3->mp3FrameChannels = info.channels;
pMP3->mp3FrameSampleRate = info.hz;
break;
} else if (info.frame_bytes == 0) {
size_t bytesRead;
memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
pMP3->dataConsumed = 0;
if (pMP3->dataCapacity == pMP3->dataSize) {
drmp3_uint8* pNewData;
size_t newDataCap;
newDataCap = pMP3->dataCapacity + DRMP3_DATA_CHUNK_SIZE;
pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
if (pNewData == NULL) {
return 0;
}
pMP3->pData = pNewData;
pMP3->dataCapacity = newDataCap;
}
bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
if (bytesRead == 0) {
pMP3->atEnd = DRMP3_TRUE;
return 0;
}
pMP3->dataSize += bytesRead;
}
};
return pcmFramesRead;
}
static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
{
drmp3_uint32 pcmFramesRead = 0;
drmp3dec_frame_info info;
DRMP3_ASSERT(pMP3 != NULL);
DRMP3_ASSERT(pMP3->memory.pData != NULL);
if (pMP3->atEnd) {
return 0;
}
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
if (pcmFramesRead > 0) {
pMP3->pcmFramesConsumedInMP3Frame = 0;
pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
pMP3->mp3FrameChannels = info.channels;
pMP3->mp3FrameSampleRate = info.hz;
}
pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
return pcmFramesRead;
}
static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
{
if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) {
return drmp3_decode_next_frame_ex__memory(pMP3, pPCMFrames);
} else {
return drmp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames);
}
}
static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3)
{
DRMP3_ASSERT(pMP3 != NULL);
return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames);
}
#if 0
static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3)
{
drmp3_uint32 pcmFrameCount;
DRMP3_ASSERT(pMP3 != NULL);
pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL);
if (pcmFrameCount == 0) {
return 0;
}
pMP3->currentPCMFrame += pcmFrameCount;
pMP3->pcmFramesConsumedInMP3Frame = pcmFrameCount;
pMP3->pcmFramesRemainingInMP3Frame = 0;
return pcmFrameCount;
}
#endif
static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
DRMP3_ASSERT(pMP3 != NULL);
DRMP3_ASSERT(onRead != NULL);
drmp3dec_init(&pMP3->decoder);
pMP3->onRead = onRead;
pMP3->onSeek = onSeek;
pMP3->pUserData = pUserData;
pMP3->allocationCallbacks = drmp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) {
return DRMP3_FALSE;
}
if (!drmp3_decode_next_frame(pMP3)) {
drmp3_uninit(pMP3);
return DRMP3_FALSE;
}
pMP3->channels = pMP3->mp3FrameChannels;
pMP3->sampleRate = pMP3->mp3FrameSampleRate;
return DRMP3_TRUE;
}
DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pMP3 == NULL || onRead == NULL) {
return DRMP3_FALSE;
}
DRMP3_ZERO_OBJECT(pMP3);
return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks);
}
static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
drmp3* pMP3 = (drmp3*)pUserData;
size_t bytesRemaining;
DRMP3_ASSERT(pMP3 != NULL);
DRMP3_ASSERT(pMP3->memory.dataSize >= pMP3->memory.currentReadPos);
bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos;
if (bytesToRead > bytesRemaining) {
bytesToRead = bytesRemaining;
}
if (bytesToRead > 0) {
DRMP3_COPY_MEMORY(pBufferOut, pMP3->memory.pData + pMP3->memory.currentReadPos, bytesToRead);
pMP3->memory.currentReadPos += bytesToRead;
}
return bytesToRead;
}
static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin)
{
drmp3* pMP3 = (drmp3*)pUserData;
DRMP3_ASSERT(pMP3 != NULL);
if (origin == drmp3_seek_origin_current) {
if (byteOffset > 0) {
if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) {
byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos);
}
} else {
if (pMP3->memory.currentReadPos < (size_t)-byteOffset) {
byteOffset = -(int)pMP3->memory.currentReadPos;
}
}
pMP3->memory.currentReadPos += byteOffset;
} else {
if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) {
pMP3->memory.currentReadPos = byteOffset;
} else {
pMP3->memory.currentReadPos = pMP3->memory.dataSize;
}
}
return DRMP3_TRUE;
}
DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pMP3 == NULL) {
return DRMP3_FALSE;
}
DRMP3_ZERO_OBJECT(pMP3);
if (pData == NULL || dataSize == 0) {
return DRMP3_FALSE;
}
pMP3->memory.pData = (const drmp3_uint8*)pData;
pMP3->memory.dataSize = dataSize;
pMP3->memory.currentReadPos = 0;
return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pAllocationCallbacks);
}
#ifndef DR_MP3_NO_STDIO
#include <stdio.h>
#include <wchar.h>
#include <errno.h>
static drmp3_result drmp3_result_from_errno(int e)
{
switch (e)
{
case 0: return DRMP3_SUCCESS;
#ifdef EPERM
case EPERM: return DRMP3_INVALID_OPERATION;
#endif
#ifdef ENOENT
case ENOENT: return DRMP3_DOES_NOT_EXIST;
#endif
#ifdef ESRCH
case ESRCH: return DRMP3_DOES_NOT_EXIST;
#endif
#ifdef EINTR
case EINTR: return DRMP3_INTERRUPT;
#endif
#ifdef EIO
case EIO: return DRMP3_IO_ERROR;
#endif
#ifdef ENXIO
case ENXIO: return DRMP3_DOES_NOT_EXIST;
#endif
#ifdef E2BIG
case E2BIG: return DRMP3_INVALID_ARGS;
#endif
#ifdef ENOEXEC
case ENOEXEC: return DRMP3_INVALID_FILE;
#endif
#ifdef EBADF
case EBADF: return DRMP3_INVALID_FILE;
#endif
#ifdef ECHILD
case ECHILD: return DRMP3_ERROR;
#endif
#ifdef EAGAIN
case EAGAIN: return DRMP3_UNAVAILABLE;
#endif
#ifdef ENOMEM
case ENOMEM: return DRMP3_OUT_OF_MEMORY;
#endif
#ifdef EACCES
case EACCES: return DRMP3_ACCESS_DENIED;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#endif
#ifdef EKEYREJECTED
case EKEYREJECTED: return DRMP3_ERROR;
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD: return DRMP3_ERROR;
#endif
#ifdef ENOTRECOVERABLE
case ENOTRECOVERABLE: return DRMP3_ERROR;
#endif
#ifdef ERFKILL
case ERFKILL: return DRMP3_ERROR;
#endif
#ifdef EHWPOISON
case EHWPOISON: return DRMP3_ERROR;
#endif
default: return DRMP3_ERROR;
}
}
static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{
#if _MSC_VER && _MSC_VER >= 1400
errno_t err;
#endif
if (ppFile != NULL) {
*ppFile = NULL;
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return DRMP3_INVALID_ARGS;
}
#if _MSC_VER && _MSC_VER >= 1400
err = fopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drmp3_result_from_errno(err);
}
#else
#if defined(_WIN32) || defined(__APPLE__)
*ppFile = fopen(pFilePath, pOpenMode);
#else
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
*ppFile = fopen64(pFilePath, pOpenMode);
#else
*ppFile = fopen(pFilePath, pOpenMode);
#endif
#endif
if (*ppFile == NULL) {
drmp3_result result = drmp3_result_from_errno(errno);
if (result == DRMP3_SUCCESS) {
result = DRMP3_ERROR;
}
return result;
}
#endif
return DRMP3_SUCCESS;
}
#if defined(_WIN32)
#if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
#define DRMP3_HAS_WFOPEN
#endif
#endif
static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (ppFile != NULL) {
*ppFile = NULL;
}
if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
return DRMP3_INVALID_ARGS;
}
#if defined(DRMP3_HAS_WFOPEN)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drmp3_result_from_errno(err);
}
#else
*ppFile = _wfopen(pFilePath, pOpenMode);
if (*ppFile == NULL) {
return drmp3_result_from_errno(errno);
}
#endif
(void)pAllocationCallbacks;
}
#else
{
mbstate_t mbs;
size_t lenMB;
const wchar_t* pFilePathTemp = pFilePath;
char* pFilePathMB = NULL;
char pOpenModeMB[32] = {0};
DRMP3_ZERO_OBJECT(&mbs);
lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
if (lenMB == (size_t)-1) {
return drmp3_result_from_errno(errno);
}
pFilePathMB = (char*)drmp3__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
if (pFilePathMB == NULL) {
return DRMP3_OUT_OF_MEMORY;
}
pFilePathTemp = pFilePath;
DRMP3_ZERO_OBJECT(&mbs);
wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
{
size_t i = 0;
for (;;) {
if (pOpenMode[i] == 0) {
pOpenModeMB[i] = '\0';
break;
}
pOpenModeMB[i] = (char)pOpenMode[i];
i += 1;
}
}
*ppFile = fopen(pFilePathMB, pOpenModeMB);
drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
}
if (*ppFile == NULL) {
return DRMP3_ERROR;
}
#endif
return DRMP3_SUCCESS;
}
static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
{
return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
}
static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek_origin origin)
{
return fseek((FILE*)pUserData, offset, (origin == drmp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
}
DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
FILE* pFile;
if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) {
return DRMP3_FALSE;
}
return drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
}
DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
FILE* pFile;
if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) {
return DRMP3_FALSE;
}
return drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
}
#endif
DRMP3_API void drmp3_uninit(drmp3* pMP3)
{
if (pMP3 == NULL) {
return;
}
#ifndef DR_MP3_NO_STDIO
if (pMP3->onRead == drmp3__on_read_stdio) {
fclose((FILE*)pMP3->pUserData);
}
#endif
drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks);
}
#if defined(DR_MP3_FLOAT_OUTPUT)
static void drmp3_f32_to_s16(drmp3_int16* dst, const float* src, drmp3_uint64 sampleCount)
{
drmp3_uint64 i;
drmp3_uint64 i4;
drmp3_uint64 sampleCount4;
i = 0;
sampleCount4 = sampleCount >> 2;
for (i4 = 0; i4 < sampleCount4; i4 += 1) {
float x0 = src[i+0];
float x1 = src[i+1];
float x2 = src[i+2];
float x3 = src[i+3];
x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
x0 = x0 * 32767.0f;
x1 = x1 * 32767.0f;
x2 = x2 * 32767.0f;
x3 = x3 * 32767.0f;
dst[i+0] = (drmp3_int16)x0;
dst[i+1] = (drmp3_int16)x1;
dst[i+2] = (drmp3_int16)x2;
dst[i+3] = (drmp3_int16)x3;
i += 4;
}
for (; i < sampleCount; i += 1) {
float x = src[i];
x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
x = x * 32767.0f;
dst[i] = (drmp3_int16)x;
}
}
#endif
#if !defined(DR_MP3_FLOAT_OUTPUT)
static void drmp3_s16_to_f32(float* dst, const drmp3_int16* src, drmp3_uint64 sampleCount)
{
drmp3_uint64 i;
for (i = 0; i < sampleCount; i += 1) {
float x = (float)src[i];
x = x * 0.000030517578125f;
dst[i] = x;
}
}
#endif
static drmp3_uint64 drmp3_read_pcm_frames_raw(drmp3* pMP3, drmp3_uint64 framesToRead, void* pBufferOut)
{
drmp3_uint64 totalFramesRead = 0;
DRMP3_ASSERT(pMP3 != NULL);
DRMP3_ASSERT(pMP3->onRead != NULL);
while (framesToRead > 0) {
drmp3_uint32 framesToConsume = (drmp3_uint32)DRMP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead);
if (pBufferOut != NULL) {
#if defined(DR_MP3_FLOAT_OUTPUT)
float* pFramesOutF32 = (float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels);
float* pFramesInF32 = (float*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
DRMP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels);
#else
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame;
pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
break;
}
drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
}
}
}
if (!drmp3_seek_to_start_of_stream(pMP3)) {
return DRMP3_FALSE;
}
if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
return DRMP3_FALSE;
}
}
*pSeekPointCount = seekPointCount;
return DRMP3_TRUE;
}
DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints)
{
if (pMP3 == NULL) {
return DRMP3_FALSE;
}
if (seekPointCount == 0 || pSeekPoints == NULL) {
pMP3->seekPointCount = 0;
pMP3->pSeekPoints = NULL;
} else {
pMP3->seekPointCount = seekPointCount;
pMP3->pSeekPoints = pSeekPoints;
}
return DRMP3_TRUE;
}
static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
{
drmp3_uint64 totalFramesRead = 0;
drmp3_uint64 framesCapacity = 0;
float* pFrames = NULL;
float temp[4096];
DRMP3_ASSERT(pMP3 != NULL);
for (;;) {
drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp);
if (framesJustRead == 0) {
break;
}
if (framesCapacity < totalFramesRead + framesJustRead) {
drmp3_uint64 oldFramesBufferSize;
drmp3_uint64 newFramesBufferSize;
drmp3_uint64 newFramesCap;
float* pNewFrames;
newFramesCap = framesCapacity * 2;
if (newFramesCap < totalFramesRead + framesJustRead) {
newFramesCap = totalFramesRead + framesJustRead;
}
oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float);
newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float);
if (newFramesBufferSize > DRMP3_SIZE_MAX) {
break;
}
pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
if (pNewFrames == NULL) {
drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
break;
}
pFrames = pNewFrames;
framesCapacity = newFramesCap;
}
DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float)));
totalFramesRead += framesJustRead;
if (framesJustRead != framesToReadRightNow) {
break;
}
}
if (pConfig != NULL) {
pConfig->channels = pMP3->channels;
pConfig->sampleRate = pMP3->sampleRate;
}
drmp3_uninit(pMP3);
if (pTotalFrameCount) {
*pTotalFrameCount = totalFramesRead;
}
return pFrames;
}
static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
{
drmp3_uint64 totalFramesRead = 0;
drmp3_uint64 framesCapacity = 0;
drmp3_int16* pFrames = NULL;
drmp3_int16 temp[4096];
DRMP3_ASSERT(pMP3 != NULL);
for (;;) {
drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp);
if (framesJustRead == 0) {
break;
}
if (framesCapacity < totalFramesRead + framesJustRead) {
drmp3_uint64 newFramesBufferSize;
drmp3_uint64 oldFramesBufferSize;
drmp3_uint64 newFramesCap;
drmp3_int16* pNewFrames;
newFramesCap = framesCapacity * 2;
if (newFramesCap < totalFramesRead + framesJustRead) {
newFramesCap = totalFramesRead + framesJustRead;
}
oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16);
newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16);
if (newFramesBufferSize > DRMP3_SIZE_MAX) {
break;
}
pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
if (pNewFrames == NULL) {
drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
break;
}
pFrames = pNewFrames;
framesCapacity = newFramesCap;
}
DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16)));
totalFramesRead += framesJustRead;
if (framesJustRead != framesToReadRightNow) {
break;
}
}
if (pConfig != NULL) {
pConfig->channels = pMP3->channels;
pConfig->sampleRate = pMP3->sampleRate;
}
drmp3_uninit(pMP3);
if (pTotalFrameCount) {
*pTotalFrameCount = totalFramesRead;
}
return pFrames;
}
DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3 mp3;
if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
return NULL;
}
return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
}
DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3 mp3;
if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
return NULL;
}
return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
}
DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3 mp3;
if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
return NULL;
}
return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
}
DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3 mp3;
if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
return NULL;
}
return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
}
#ifndef DR_MP3_NO_STDIO
DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3 mp3;
if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
return NULL;
}
return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
}
DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3 mp3;
if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
return NULL;
}
return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
}
#endif
DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
return drmp3__malloc_from_callbacks(sz, pAllocationCallbacks);
} else {
return drmp3__malloc_default(sz, NULL);
}
}
DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
drmp3__free_from_callbacks(p, pAllocationCallbacks);
} else {
drmp3__free_default(p, NULL);
}
}
#endif
/* dr_mp3_c end */
#endif /* DRMP3_IMPLEMENTATION */
#endif /* MA_NO_MP3 */
/* End globally disabled warnings. */
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif /* miniaudio_c */
#endif /* MINIAUDIO_IMPLEMENTATION */
/*
RELEASE NOTES - VERSION 0.10.x
==============================
Version 0.10 includes major API changes and refactoring, mostly concerned with the data conversion system. Data conversion is performed internally to convert
audio data between the format requested when initializing the `ma_device` object and the format of the internal device used by the backend. The same applies
to the `ma_decoder` object. The previous design has several design flaws and missing features which necessitated a complete redesign.
Changes to Data Conversion
--------------------------
The previous data conversion system used callbacks to deliver input data for conversion. This design works well in some specific situations, but in other
situations it has some major readability and maintenance issues. The decision was made to replace this with a more iterative approach where you just pass in a
pointer to the input data directly rather than dealing with a callback.
The following are the data conversion APIs that have been removed and their replacements:
- ma_format_converter -> ma_convert_pcm_frames_format()
- ma_channel_router -> ma_channel_converter
- ma_src -> ma_resampler
- ma_pcm_converter -> ma_data_converter
The previous conversion APIs accepted a callback in their configs. There are no longer any callbacks to deal with. Instead you just pass the data into the
`*_process_pcm_frames()` function as a pointer to a buffer.
The simplest aspect of data conversion is sample format conversion. To convert between two formats, just call `ma_convert_pcm_frames_format()`. Channel
conversion is also simple which you can do with `ma_channel_converter` via `ma_channel_converter_process_pcm_frames()`.
Resampling is more complicated because the number of output frames that are processed is different to the number of input frames that are consumed. When you
call `ma_resampler_process_pcm_frames()` you need to pass in the number of input frames available for processing and the number of output frames you want to
output. Upon returning they will receive the number of input frames that were consumed and the number of output frames that were generated.
The `ma_data_converter` API is a wrapper around format, channel and sample rate conversion and handles all of the data conversion you'll need which probably
makes it the best option if you need to do data conversion.
In addition to changes to the API design, a few other changes have been made to the data conversion pipeline:
- The sinc resampler has been removed. This was completely broken and never actually worked properly.
- The linear resampler now uses low-pass filtering to remove aliasing. The quality of the low-pass filter can be controlled via the resampler config with the
`lpfOrder` option, which has a maximum value of MA_MAX_FILTER_ORDER.
- Data conversion now supports s16 natively which runs through a fixed point pipeline. Previously everything needed to be converted to floating point before
processing, whereas now both s16 and f32 are natively supported. Other formats still require conversion to either s16 or f32 prior to processing, however
`ma_data_converter` will handle this for you.
Custom Memory Allocators
------------------------
miniaudio has always supported macro level customization for memory allocation via MA_MALLOC, MA_REALLOC and MA_FREE, however some scenarios require more
flexibility by allowing a user data pointer to be passed to the custom allocation routines. Support for this has been added to version 0.10 via the
`ma_allocation_callbacks` structure. Anything making use of heap allocations has been updated to accept this new structure.
The `ma_context_config` structure has been updated with a new member called `allocationCallbacks`. Leaving this set to it's defaults returned by
`ma_context_config_init()` will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. Likewise, The `ma_decoder_config` structure has been updated in the same
way, and leaving everything as-is after `ma_decoder_config_init()` will cause it to use the same defaults.
The following APIs have been updated to take a pointer to a `ma_allocation_callbacks` object. Setting this parameter to NULL will cause it to use defaults.
Otherwise they will use the relevant callback in the structure.
- ma_malloc()
- ma_realloc()
- ma_free()
- ma_aligned_malloc()
- ma_aligned_free()
- ma_rb_init() / ma_rb_init_ex()
- ma_pcm_rb_init() / ma_pcm_rb_init_ex()
Note that you can continue to use MA_MALLOC, MA_REALLOC and MA_FREE as per normal. These will continue to be used by default if you do not specify custom
allocation callbacks.
Buffer and Period Configuration Changes
---------------------------------------
The way in which the size of the internal buffer and periods are specified in the device configuration have changed. In previous versions, the config variables
`bufferSizeInFrames` and `bufferSizeInMilliseconds` defined the size of the entire buffer, with the size of a period being the size of this variable divided by
the period count. This became confusing because people would expect the value of `bufferSizeInFrames` or `bufferSizeInMilliseconds` to independantly determine
latency, when in fact it was that value divided by the period count that determined it. These variables have been removed and replaced with new ones called
`periodSizeInFrames` and `periodSizeInMilliseconds`.
These new configuration variables work in the same way as their predecessors in that if one is set to 0, the other will be used, but the main difference is
that you now set these to you desired latency rather than the size of the entire buffer. The benefit of this is that it's much easier and less confusing to
configure latency.
The following unused APIs have been removed:
ma_get_default_buffer_size_in_milliseconds()
ma_get_default_buffer_size_in_frames()
The following macros have been removed:
MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY
MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE
Other API Changes
-----------------
Other less major API changes have also been made in version 0.10.
`ma_device_set_stop_callback()` has been removed. If you require a stop callback, you must now set it via the device config just like the data callback.
The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including
sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes a configuration
object called `ma_waveform_config` which defines the properties of the waveform. Use `ma_waveform_config_init()` to initialize a `ma_waveform_config` object.
Use `ma_waveform_read_pcm_frames()` in place of `ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`.
`ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies
the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to
take a pointer to a `ma_data_converter_config` object to specify the input and output formats to convert between. This was done to make it more flexible, to
prevent the parameter list getting too long, and to prevent API breakage whenever a new conversion property is added.
`ma_calculate_frame_count_after_src()` has been renamed to `ma_calculate_frame_count_after_resampling()` for consistency with the new `ma_resampler` API.
Filters
-------
The following filters have been added:
|-------------|-------------------------------------------------------------------|
| API | Description |
|-------------|-------------------------------------------------------------------|
| ma_biquad | Biquad filter (transposed direct form 2) |
| ma_lpf1 | First order low-pass filter |
| ma_lpf2 | Second order low-pass filter |
| ma_lpf | High order low-pass filter (Butterworth) |
| ma_hpf1 | First order high-pass filter |
| ma_hpf2 | Second order high-pass filter |
| ma_hpf | High order high-pass filter (Butterworth) |
| ma_bpf2 | Second order band-pass filter |
| ma_bpf | High order band-pass filter |
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
object. Then use `ma_noise_read_pcm_frames()` to read PCM data.
Miscellaneous Changes
---------------------
The MA_NO_STDIO option has been removed. This would disable file I/O APIs, however this has proven to be too hard to maintain for it's perceived value and was
therefore removed.
Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report.
The `ma_device` structure is no longer defined as being aligned to MA_SIMD_ALIGNMENT. This resulted in a possible crash when allocating a `ma_device` object on
the heap, but not aligning it to MA_SIMD_ALIGNMENT. This crash would happen due to the compiler seeing the alignment specified on the structure and assuming it
was always aligned as such and thinking it was safe to emit alignment-dependant SIMD instructions. Since miniaudio's philosophy is for things to just work,
this has been removed from all structures.
Results codes have been overhauled. Unnecessary result codes have been removed, and some have been renumbered for organisation purposes. If you are are binding
maintainer you will need to update your result codes. Support has also been added for retrieving a human readable description of a given result code via the
`ma_result_description()` API.
ALSA: The automatic format conversion, channel conversion and resampling performed by ALSA is now disabled by default as they were causing some compatibility
issues with certain devices and configurations. These can be individually enabled via the device config:
```c
deviceConfig.alsa.noAutoFormat = MA_TRUE;
deviceConfig.alsa.noAutoChannels = MA_TRUE;
deviceConfig.alsa.noAutoResample = MA_TRUE;
```
*/
/*
RELEASE NOTES - VERSION 0.9.x
=============================
Version 0.9 includes major API changes, centered mostly around full-duplex and the rebrand to "miniaudio". Before I go into detail about the major changes I
would like to apologize. I know it's annoying dealing with breaking API changes, but I think it's best to get these changes out of the way now while the
library is still relatively young and unknown.
There's been a lot of refactoring with this release so there's a good chance a few bugs have been introduced. I apologize in advance for this. You may want to
hold off on upgrading for the short term if you're worried. If mini_al v0.8.14 works for you, and you don't need full-duplex support, you can avoid upgrading
(though you won't be getting future bug fixes).
Rebranding to "miniaudio"
-------------------------
The decision was made to rename mini_al to miniaudio. Don't worry, it's the same project. The reason for this is simple:
1) Having the word "audio" in the title makes it immediately clear that the library is related to audio; and
2) I don't like the look of the underscore.
This rebrand has necessitated a change in namespace from "mal" to "ma". I know this is annoying, and I apologize, but it's better to get this out of the road
now rather than later. Also, since there are necessary API changes for full-duplex support I think it's better to just get the namespace change over and done
with at the same time as the full-duplex changes. I'm hoping this will be the last of the major API changes. Fingers crossed!
The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's your preference.
Full-Duplex Support
-------------------
The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes.
1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted to avoid a third callback just
for full-duplex so the decision was made to break this API and unify the callbacks. Now, there is just one callback which is the same for all three modes
(playback, capture, duplex). The new callback looks like the following:
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In playback-only mode, pInput will be
null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer returned from the callback since it's not necessary for miniaudio
anymore.
2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client to choose a different PCM format
for the playback and capture sides. The old ma_device_config object simply did not allow this and needed to change. With these changes you now specify the
device ID, format, channels, channel map and share mode on a per-playback and per-capture basis (see example below). The sample rate must be the same for
playback and capture.
Since the device config API has changed I have also decided to take the opportunity to simplify device initialization. Now, the device ID, device type and
callback user data are set in the config. ma_device_init() is now simplified down to taking just the context, device config and a pointer to the device
object being initialized. The rationale for this change is that it just makes more sense to me that these are set as part of the config like everything
else.
Example device initialization:
ma_device_config config = ma_device_config_init(ma_device_type_duplex); // Or ma_device_type_playback or ma_device_type_capture.
config.playback.pDeviceID = &myPlaybackDeviceID; // Or NULL for the default playback device.
config.playback.format = ma_format_f32;
config.playback.channels = 2;
config.capture.pDeviceID = &myCaptureDeviceID; // Or NULL for the default capture device.
config.capture.format = ma_format_s16;
config.capture.channels = 1;
config.sampleRate = 44100;
config.dataCallback = data_callback;
config.pUserData = &myUserData;
result = ma_device_init(&myContext, &config, &device);
if (result != MA_SUCCESS) {
... handle error ...
}
Note that the "onDataCallback" member of ma_device_config has been renamed to "dataCallback". Also, "onStopCallback" has been renamed to "stopCallback".
This is the first pass for full-duplex and there is a known bug. You will hear crackling on the following backends when sample rate conversion is required for
the playback device:
- Core Audio
- JACK
- AAudio
- OpenSL
- WebAudio
In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such thorough testing. If you
experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample program that reproduces the issue if possible).
Other API Changes
-----------------
In addition to the above, the following API changes have been made:
- The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization.
- The onLogCallback member of ma_context_config has been renamed to "logCallback".
- The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
- You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it.
- Some APIs have been renamed:
- mal_decoder_read() -> ma_decoder_read_pcm_frames()
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
v0.10.7 - 2020-05-25
- Fix a compilation error in the C++ build.
- Silence a warning.
v0.10.6 - 2020-05-24
- Change ma_clip_samples_f32() and ma_clip_pcm_frames_f32() to take a 64-bit sample/frame count.
- Change ma_zero_pcm_frames() to clear to 128 for ma_format_u8.
- Add ma_silence_pcm_frames() which replaces ma_zero_pcm_frames(). ma_zero_pcm_frames() will be removed in version 0.11.
- Add support for u8, s24 and s32 formats to ma_channel_converter.
- Add compile-time and run-time version querying.
- MA_VERSION_MINOR
- MA_VERSION_MAJOR
- MA_VERSION_REVISION
- MA_VERSION_STRING
- ma_version()
- ma_version_string()
- Add ma_audio_buffer for reading raw audio data directly from memory.
- Fix a bug in shuffle mode in ma_channel_converter.
- Fix compilation errors in certain configurations for ALSA and PulseAudio.
- The data callback now initializes the output buffer to 128 when the playback sample format is ma_format_u8.
v0.10.5 - 2020-05-05
- Change ma_zero_pcm_frames() to take a 64-bit frame count.
- Add ma_copy_pcm_frames().
- Add MA_NO_GENERATION build option to exclude the `ma_waveform` and `ma_noise` APIs from the build.
- Add support for formatted logging to the VC6 build.
- Fix a crash in the linear resampler when LPF order is 0.
- Fix compilation errors and warnings with older versions of Visual Studio.
- Minor documentation updates.
v0.10.4 - 2020-04-12
- Fix a data conversion bug when converting from the client format to the native device format.
v0.10.3 - 2020-04-07
- Bring up to date with breaking changes to dr_mp3.
- Remove MA_NO_STDIO. This was causing compilation errors and the maintenance cost versus practical benefit is no longer worthwhile.
- Fix a bug with data conversion where it was unnecessarily converting to s16 or f32 and then straight back to the original format.
- Fix compilation errors and warnings with Visual Studio 2005.
- ALSA: Disable ALSA's automatic data conversion by default and add configuration options to the device config:
- alsa.noAutoFormat
- alsa.noAutoChannels
- alsa.noAutoResample
- WASAPI: Add some overrun recovery for ma_device_type_capture devices.
v0.10.2 - 2020-03-22
- Decorate some APIs with MA_API which were missed in the previous version.
- Fix a bug in ma_linear_resampler_set_rate() and ma_linear_resampler_set_rate_ratio().
v0.10.1 - 2020-03-17
- Add MA_API decoration. This can be customized by defining it before including miniaudio.h.
- Fix a bug where opening a file would return a success code when in fact it failed.
- Fix compilation errors with Visual Studio 6 and 2003.
- Fix warnings on macOS.
v0.10.0 - 2020-03-07
- API CHANGE: Refactor data conversion APIs
- ma_format_converter has been removed. Use ma_convert_pcm_frames_format() instead.
- ma_channel_router has been replaced with ma_channel_converter.
- ma_src has been replaced with ma_resampler
- ma_pcm_converter has been replaced with ma_data_converter
- API CHANGE: Add support for custom memory allocation callbacks. The following APIs have been updated to take an extra parameter for the allocation
callbacks:
- ma_malloc()
- ma_realloc()
- ma_free()
- ma_aligned_malloc()
- ma_aligned_free()
- ma_rb_init() / ma_rb_init_ex()
- ma_pcm_rb_init() / ma_pcm_rb_init_ex()
- API CHANGE: Simplify latency specification in device configurations. The bufferSizeInFrames and bufferSizeInMilliseconds parameters have been replaced with
periodSizeInFrames and periodSizeInMilliseconds respectively. The previous variables defined the size of the entire buffer, whereas the new ones define the
size of a period. The following APIs have been removed since they are no longer relevant:
- ma_get_default_buffer_size_in_milliseconds()
- ma_get_default_buffer_size_in_frames()
- API CHANGE: ma_device_set_stop_callback() has been removed. If you require a stop callback, you must now set it via the device config just like the data
callback.
- API CHANGE: The ma_sine_wave API has been replaced with ma_waveform. The following APIs have been removed:
- ma_sine_wave_init()
- ma_sine_wave_read_f32()
- ma_sine_wave_read_f32_ex()
- API CHANGE: ma_convert_frames() has been updated to take an extra parameter which is the size of the output buffer in PCM frames. Parameters have also been
reordered.
- API CHANGE: ma_convert_frames_ex() has been changed to take a pointer to a ma_data_converter_config object to specify the input and output formats to
convert between.
- API CHANGE: ma_calculate_frame_count_after_src() has been renamed to ma_calculate_frame_count_after_resampling().
- Add support for the following filters:
- Biquad (ma_biquad)
- First order low-pass (ma_lpf1)
- Second order low-pass (ma_lpf2)
- Low-pass with configurable order (ma_lpf)
- First order high-pass (ma_hpf1)
- Second order high-pass (ma_hpf2)
- High-pass with configurable order (ma_hpf)
- Second order band-pass (ma_bpf2)
- Band-pass with configurable order (ma_bpf)
- Second order peaking EQ (ma_peak2)
- Second order notching (ma_notch2)
- Second order low shelf (ma_loshelf2)
- Second order high shelf (ma_hishelf2)
- Add waveform generation API (ma_waveform) with support for the following:
- Sine
- Square
- Triangle
- Sawtooth
- Add noise generation API (ma_noise) with support for the following:
- White
- Pink
- Brownian
- Add encoding API (ma_encoder). This only supports outputting to WAV files via dr_wav.
- Add ma_result_description() which is used to retrieve a human readable description of a given result code.
- Result codes have been changed. Binding maintainers will need to update their result code constants.
- More meaningful result codes are now returned when a file fails to open.
- Internal functions have all been made static where possible.
- Fix potential crash when ma_device object's are not aligned to MA_SIMD_ALIGNMENT.
- Fix a bug in ma_decoder_get_length_in_pcm_frames() where it was returning the length based on the internal sample rate rather than the output sample rate.
- Fix bugs in some backends where the device is not drained properly in ma_device_stop().
- Improvements to documentation.
v0.9.10 - 2020-01-15
- Fix compilation errors due to #if/#endif mismatches.
- WASAPI: Fix a bug where automatic stream routing is being performed for devices that are initialized with an explicit device ID.
- iOS: Fix a crash on device uninitialization.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- 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.