view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
// 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.
11.2. PulseAudio
----------------
- If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki:
https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. Alternatively, consider using a different backend such as ALSA.
11.3. Android
-------------
- To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: `<uses-permission android:name="android.permission.RECORD_AUDIO" />`
- With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES.
- With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
} ma_resample_algorithm;
typedef struct
{
ma_format format; /* Must be either ma_format_f32 or ma_format_s16. */
ma_uint32 channels;
ma_uint32 sampleRateIn;
ma_uint32 sampleRateOut;
ma_resample_algorithm algorithm;
struct
{
ma_uint32 lpfOrder;
double lpfNyquistFactor;
} linear;
struct
{
int quality; /* 0 to 10. Defaults to 3. */
} speex;
} ma_resampler_config;
MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm);
typedef struct
{
ma_resampler_config config;
union
{
ma_linear_resampler linear;
struct
{
void* pSpeexResamplerState; /* SpeexResamplerState* */
} speex;
} state;
} ma_resampler;
/*
Initializes a new resampler object from a config.
*/
MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler);
/*
Uninitializes a resampler.
*/
MA_API void ma_resampler_uninit(ma_resampler* pResampler);
/*
Converts the given input data.
Both the input and output frames must be in the format specified in the config when the resampler was initilized.
On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that
were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use
ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames.
On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole
input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames
you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead.
If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of
output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input
frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be
processed. In this case, any internal filter state will be updated as if zeroes were passed in.
It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL.
It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
*/
MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
/*
Sets the input and output sample sample rate.
*/
MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
/*
Sets the input and output sample rate as a ratio.
The ration is in/out.
*/
MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio);
/*
Calculates the number of whole input frames that would need to be read from the client in order to output the specified
number of output frames.
The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
read from the input buffer in order to output the specified number of output frames.
*/
MA_API ma_uint64 ma_resampler_get_required_input_frame_count(ma_resampler* pResampler, ma_uint64 outputFrameCount);
/*
Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
input frames.
*/
MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(ma_resampler* pResampler, ma_uint64 inputFrameCount);
/*
Retrieves the latency introduced by the resampler in input frames.
*/
MA_API ma_uint64 ma_resampler_get_input_latency(ma_resampler* pResampler);
/*
Retrieves the latency introduced by the resampler in output frames.
*/
MA_API ma_uint64 ma_resampler_get_output_latency(ma_resampler* pResampler);
/**************************************************************************************************************************************************************
Channel Conversion
**************************************************************************************************************************************************************/
typedef struct
{
ma_format format;
ma_uint32 channelsIn;
ma_uint32 channelsOut;
ma_channel channelMapIn[MA_MAX_CHANNELS];
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
/*SLObjectItf*/ ma_ptr pAudioPlayerObj;
/*SLPlayItf*/ ma_ptr pAudioPlayer;
/*SLObjectItf*/ ma_ptr pAudioRecorderObj;
/*SLRecordItf*/ ma_ptr pAudioRecorder;
/*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
/*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
ma_bool32 isDrainingCapture;
ma_bool32 isDrainingPlayback;
ma_uint32 currentBufferIndexPlayback;
ma_uint32 currentBufferIndexCapture;
ma_uint8* pBufferPlayback; /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
ma_uint8* pBufferCapture;
ma_pcm_rb duplexRB;
} opensl;
#endif
#ifdef MA_SUPPORT_WEBAUDIO
struct
{
int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
int indexCapture;
ma_pcm_rb duplexRB; /* In external capture format. */
} webaudio;
#endif
#ifdef MA_SUPPORT_NULL
struct
{
ma_thread deviceThread;
ma_event operationEvent;
ma_event operationCompletionEvent;
ma_uint32 operation;
ma_result operationResult;
ma_timer timer;
double priorRunTime;
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint64 lastProcessedFrameCapture;
ma_bool32 isStarted;
} null_device;
#endif
};
};
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#else
#pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
#endif
/*
Initializes a `ma_context_config` object.
Return Value
------------
A `ma_context_config` initialized to defaults.
Remarks
-------
You must always use this to initialize the default state of the `ma_context_config` object. Not using this will result in your program breaking when miniaudio
is updated and new members are added to `ma_context_config`. It also sets logical defaults.
You can override members of the returned object by changing it's members directly.
See Also
--------
ma_context_init()
*/
MA_API ma_context_config ma_context_config_init(void);
/*
Initializes a context.
The context is used for selecting and initializing an appropriate backend and to represent the backend at a more global level than that of an individual
device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices.
Parameters
----------
backends (in, optional)
A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
backendCount (in, optional)
The number of items in `backend`. Ignored if `backend` is NULL.
pConfig (in, optional)
The context configuration.
pContext (in)
A pointer to the context object being initialized.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
Remarks
-------
When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
|-------------|-----------------------|--------------------------------------------------------|
| Name | Enum Name | Supported Operating Systems |
|-------------|-----------------------|--------------------------------------------------------|
| WASAPI | ma_backend_wasapi | Windows Vista+ |
| DirectSound | ma_backend_dsound | Windows XP+ |
| WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) |
| Core Audio | ma_backend_coreaudio | macOS, iOS |
| ALSA | ma_backend_alsa | Linux |
| PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) |
| JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) |
| sndio | ma_backend_sndio | OpenBSD |
| audio(4) | ma_backend_audio4 | NetBSD, OpenBSD |
| OSS | ma_backend_oss | FreeBSD |
| AAudio | ma_backend_aaudio | Android 8+ |
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
case kAudioChannelLabel_Discrete_10: return MA_CHANNEL_AUX_10;
case kAudioChannelLabel_Discrete_11: return MA_CHANNEL_AUX_11;
case kAudioChannelLabel_Discrete_12: return MA_CHANNEL_AUX_12;
case kAudioChannelLabel_Discrete_13: return MA_CHANNEL_AUX_13;
case kAudioChannelLabel_Discrete_14: return MA_CHANNEL_AUX_14;
case kAudioChannelLabel_Discrete_15: return MA_CHANNEL_AUX_15;
case kAudioChannelLabel_Discrete_65535: return MA_CHANNEL_NONE;
#if 0 /* Introduced in a later version of macOS. */
case kAudioChannelLabel_HOA_ACN: return MA_CHANNEL_NONE;
case kAudioChannelLabel_HOA_ACN_0: return MA_CHANNEL_AUX_0;
case kAudioChannelLabel_HOA_ACN_1: return MA_CHANNEL_AUX_1;
case kAudioChannelLabel_HOA_ACN_2: return MA_CHANNEL_AUX_2;
case kAudioChannelLabel_HOA_ACN_3: return MA_CHANNEL_AUX_3;
case kAudioChannelLabel_HOA_ACN_4: return MA_CHANNEL_AUX_4;
case kAudioChannelLabel_HOA_ACN_5: return MA_CHANNEL_AUX_5;
case kAudioChannelLabel_HOA_ACN_6: return MA_CHANNEL_AUX_6;
case kAudioChannelLabel_HOA_ACN_7: return MA_CHANNEL_AUX_7;
case kAudioChannelLabel_HOA_ACN_8: return MA_CHANNEL_AUX_8;
case kAudioChannelLabel_HOA_ACN_9: return MA_CHANNEL_AUX_9;
case kAudioChannelLabel_HOA_ACN_10: return MA_CHANNEL_AUX_10;
case kAudioChannelLabel_HOA_ACN_11: return MA_CHANNEL_AUX_11;
case kAudioChannelLabel_HOA_ACN_12: return MA_CHANNEL_AUX_12;
case kAudioChannelLabel_HOA_ACN_13: return MA_CHANNEL_AUX_13;
case kAudioChannelLabel_HOA_ACN_14: return MA_CHANNEL_AUX_14;
case kAudioChannelLabel_HOA_ACN_15: return MA_CHANNEL_AUX_15;
case kAudioChannelLabel_HOA_ACN_65024: return MA_CHANNEL_NONE;
#endif
default: return MA_CHANNEL_NONE;
}
}
static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel* pChannelMap, size_t channelMapCap)
{
MA_ASSERT(pChannelLayout != NULL);
if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
UInt32 iChannel;
for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions && iChannel < channelMapCap; ++iChannel) {
pChannelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel);
}
} else
#if 0
if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
/* This is the same kind of system that's used by Windows audio APIs. */
UInt32 iChannel = 0;
UInt32 iBit;
AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap;
for (iBit = 0; iBit < 32 && iChannel < channelMapCap; ++iBit) {
AudioChannelBitmap bit = bitmap & (1 << iBit);
if (bit != 0) {
pChannelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit);
}
}
} else
#endif
{
/*
Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should
be updated to determine the mapping based on the tag.
*/
UInt32 channelCount;
/* Our channel map retrieval APIs below take 32-bit integers, so we'll want to clamp the channel map capacity. */
if (channelMapCap > 0xFFFFFFFF) {
channelMapCap = 0xFFFFFFFF;
}
channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), (UInt32)channelMapCap);
switch (pChannelLayout->mChannelLayoutTag)
{
case kAudioChannelLayoutTag_Mono:
case kAudioChannelLayoutTag_Stereo:
case kAudioChannelLayoutTag_StereoHeadphones:
case kAudioChannelLayoutTag_MatrixStereo:
case kAudioChannelLayoutTag_MidSide:
case kAudioChannelLayoutTag_XY:
case kAudioChannelLayoutTag_Binaural:
case kAudioChannelLayoutTag_Ambisonic_B_Format:
{
ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap);
} break;
case kAudioChannelLayoutTag_Octagonal:
{
pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
} /* Intentional fallthrough. */
case kAudioChannelLayoutTag_Hexagonal:
{
pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
} /* Intentional fallthrough. */
case kAudioChannelLayoutTag_Pentagonal:
{
pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
} /* Intentional fallghrough. */
case kAudioChannelLayoutTag_Quadraphonic:
{
pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
pChannelMap[1] = MA_CHANNEL_RIGHT;
pChannelMap[0] = MA_CHANNEL_LEFT;
} break;
/* TODO: Add support for more tags here. */
default:
{
ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap);
} break;
}
}
return MA_SUCCESS;
}
static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */
{
AudioObjectPropertyAddress propAddressDevices;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
return MA_SUCCESS;
}
MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor)
{
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0;
if (pDecoder == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = pDecoder->readPointerInPCMFrames;
return MA_SUCCESS;
}
MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder)
{
if (pDecoder == NULL) {
return 0;
}
if (pDecoder->onGetLengthInPCMFrames) {
ma_uint64 nativeLengthInPCMFrames = pDecoder->onGetLengthInPCMFrames(pDecoder);
if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) {
return nativeLengthInPCMFrames;
} else {
return ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, pDecoder->internalSampleRate, nativeLengthInPCMFrames);
}
}
return 0;
}
MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
{
ma_result result;
ma_uint64 totalFramesReadOut;
ma_uint64 totalFramesReadIn;
void* pRunningFramesOut;
if (pDecoder == NULL) {
return 0;
}
if (pDecoder->onReadPCMFrames == NULL) {
return 0;
}
/* Fast path. */
if (pDecoder->converter.isPassthrough) {
totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, pFramesOut, frameCount);
} else {
/*
Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we
need to run through each sample because we need to ensure it's internal cache is updated.
*/
if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) {
totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, NULL, frameCount); /* All decoder backends must support passing in NULL for the output buffer. */
} else {
/* Slow path. Need to run everything through the data converter. */
totalFramesReadOut = 0;
totalFramesReadIn = 0;
pRunningFramesOut = pFramesOut;
while (totalFramesReadOut < frameCount) {
ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */
ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
ma_uint64 framesToReadThisIterationIn;
ma_uint64 framesReadThisIterationIn;
ma_uint64 framesToReadThisIterationOut;
ma_uint64 framesReadThisIterationOut;
ma_uint64 requiredInputFrameCount;
framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
framesToReadThisIterationIn = framesToReadThisIterationOut;
if (framesToReadThisIterationIn > intermediaryBufferCap) {
framesToReadThisIterationIn = intermediaryBufferCap;
}
requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut);
if (framesToReadThisIterationIn > requiredInputFrameCount) {
framesToReadThisIterationIn = requiredInputFrameCount;
}
if (requiredInputFrameCount > 0) {
framesReadThisIterationIn = pDecoder->onReadPCMFrames(pDecoder, pIntermediaryBuffer, framesToReadThisIterationIn);
totalFramesReadIn += framesReadThisIterationIn;
}
/*
At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any
input frames, we still want to try processing frames because there may some output frames generated from cached input data.
*/
framesReadThisIterationOut = framesToReadThisIterationOut;
result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
if (result != MA_SUCCESS) {
break;
}
totalFramesReadOut += framesReadThisIterationOut;
if (pRunningFramesOut != NULL) {
pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels));
}
if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
break; /* We're done. */
}
}
}
}
pDecoder->readPointerInPCMFrames += totalFramesReadOut;
return totalFramesReadOut;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
#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:
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.
v0.9.9 - 2020-01-09
- Fix compilation errors with MinGW.
- Fix compilation errors when compiling on Apple platforms.
- WASAPI: Add support for disabling hardware offloading.
- WASAPI: Add support for disabling automatic stream routing.
- Core Audio: Fix bugs in the case where the internal device uses deinterleaved buffers.
- Core Audio: Add support for controlling the session category (AVAudioSessionCategory) and options (AVAudioSessionCategoryOptions).
- JACK: Fix bug where incorrect ports are connected.
v0.9.8 - 2019-10-07
- WASAPI: Fix a potential deadlock when starting a full-duplex device.
- WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC.
- Core Audio: Fix bugs with automatic stream routing.
- Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized
to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device
config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined.
- Add support for clipping samples after the data callback has returned. This only applies when the playback sample format is
configured as ma_format_f32. If you are doing clipping yourself, you can disable this overhead by setting noClip to true in
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma".
- API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly:
- The device type, device ID and user data pointer have moved from ma_device_init() to the config.
- All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init().
- ma_device_config_init() now takes only one parameter which is the device type. All other properties need
to be set on the returned object directly.
- The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback"
and "stopCallback".
- The ID of the physical device is now split into two: one for the playback device and the other for the
capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID".
- API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than
being separate for each. It now takes two pointers - one containing input data and the other output data. This
design in required for full-duplex. The return value is now void instead of the number of frames written. The
new callback looks like the following:
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
- API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change,
ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The
new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The
"onLog" member of ma_context_config has been renamed to "logCallback".
- API CHANGE: Remove ma_device_get_buffer_size_in_bytes().
- API CHANGE: Rename decoding APIs to "pcm_frames" convention.
- mal_decoder_read() -> ma_decoder_read_pcm_frames()
- mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
- API CHANGE: Rename sine wave reading APIs to f32 convention.
- mal_sine_wave_read() -> ma_sine_wave_read_f32()
- mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex()
- API CHANGE: Remove some deprecated APIs
- mal_device_set_recv_callback()
- mal_device_set_send_callback()
- mal_src_set_input_sample_rate()
- mal_src_set_output_sample_rate()
- API CHANGE: Add log level to the log callback. New signature:
- void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
- API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're
a binding mainainer you will need to update your result code constants.
- API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you
will need to update.
- API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to
ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*.
- API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme.
- The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation
is too inefficient right now. This will hopefully be improved at a later date.
- Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable.
With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not
automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's
what they want.
- Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and
ma_pcm_rb operates on PCM frames.
- Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously
used for web support, will be removed in a future version.
- Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts
with Android 8. OpenSL|ES is used as a fallback for older versions of Android.
- Remove OpenAL and SDL backends.
- Fix a possible deadlock when rapidly stopping the device after it has started.
- Update documentation.
- Change licensing to a choice of public domain _or_ MIT-0 (No Attribution).
v0.8.14 - 2018-12-16
- Core Audio: Fix a bug where the device state is not set correctly after stopping.
- Add support for custom weights to the channel router.
- Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav.
v0.8.13 - 2018-12-04
- Core Audio: Fix a bug with channel mapping.
- Fix a bug with channel routing where the back/left and back/right channels have the wrong weight.
v0.8.12 - 2018-11-27
- Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2".
- Fix a linking error with ALSA.
- Fix a bug on iOS where the device name is not set correctly.
v0.8.11 - 2018-11-21
- iOS bug fixes.
- Minor tweaks to PulseAudio.
v0.8.10 - 2018-10-21
- Core Audio: Fix a hang when uninitializing a device.
- Fix a bug where an incorrect value is returned from mal_device_stop().
v0.8.9 - 2018-09-28
- Fix a bug with the SDL backend where device initialization fails.
v0.8.8 - 2018-09-14
- Fix Linux build with the ALSA backend.
- Minor documentation fix.
v0.8.7 - 2018-09-12
- Fix a bug with UWP detection.
v0.8.6 - 2018-08-26
- Automatically switch the internal device when the default device is unplugged. Note that this is still in the
early stages and not all backends handle this the same way. As of this version, this will not detect a default
device switch when changed from the operating system's audio preferences (unless the backend itself handles
this automatically). This is not supported in exclusive mode.
- WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the
user switches the default device via the operating system's audio preferences, miniaudio will automatically switch
the internal device to the new default. This is not supported in exclusive mode.
- WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer.
- WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer.
- Add support for compiling the UWP build as C.
- mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this
when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0.
v0.8.5 - 2018-08-12
- Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in
frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0
then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used.
- Add support for the audio(4) backend to OpenBSD.
- Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the
Raspberry Pi experience.
- Fix a bug where an incorrect number of samples is returned from sinc resampling.
- Add support for setting the value to be passed to internal calls to CoInitializeEx().
- WASAPI and WinMM: Stop the device when it is unplugged.
v0.8.4 - 2018-08-06
- Add sndio backend for OpenBSD.
- Add audio(4) backend for NetBSD.
- Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD.
- Formats are now native-endian (were previously little-endian).
- Mark some APIs as deprecated:
- mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate().