If we weren't able to generate any output frames it must mean we've exhausted all of our input. The only time this would not be the case is if capturedClientData was too small
If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
*/
if (capturedClientFramesToProcessThisIteration == 0) {
/* Do we actually need to wait for the device to transition into its started state? */
/* Do we actually need to wait for the device to transition into it's started state? */
/* The device should be in either a starting or started state. If it's not set to started we need to wait for it to transition. It should go from starting to started. */
Before doing any processing we need to determine how many frames we should try processing
this iteration, for both input and output. The resampler requires us to perform format and
channel conversion before passing any data into it. If we get our input count wrong, we'll
end up performing redundant pre-processing. This isn't the end of the world, but it does
end up peforming redundant pre-processing. This isn't the end of the world, but it does
result in some inefficiencies proportionate to how far our estimates are off.
If the resampler has a means to calculate exactly how much we'll need, we'll use that.
...
...
@@ -45923,7 +45923,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi
totalFramesProcessed += framesProcessed;
/*
If we encountered 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
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) {
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 its internal cache is updated.
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) {
result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut);
Job threads need to be killed first. To do this we need to post a quit message to the message queue and then wait for the thread. The quit message will never be removed from the
queue which means it will never not be returned after being encountered for the first time which means all threads will eventually receive it.
queue which means it will never not be returned after being encounted for the first time which means all threads will eventually receive it.
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Explicit cast to silence the warning. */
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
}
/*
A passthrough should never have modified the input and output frame counts. If you're
triggering these asserts you need to fix your processing callback.
triggering these assers you need to fix your processing callback.
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Explicit cast to silence the warning. */
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
@@ -3481,7 +3481,7 @@ and on output returns detailed information about the device in `ma_device_info`.
case when the device ID is NULL, in which case information about the default device needs to be retrieved.
Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created.
This is a little bit more complicated than initialization of the context due to its more complicated configuration. When initializing a
This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a
device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input,
the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to
the requested format. The conversion between the format requested by the application and the device's native format will be handled
...
...
@@ -3502,10 +3502,10 @@ asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should
The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit
easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and
`onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the
backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within its callback.
backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback.
This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback.
If the backend requires absolute flexibility with its data delivery, it can optionally implement the `onDeviceDataLoop()` callback
If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback
which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional.
The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been
...
...
@@ -4703,7 +4703,7 @@ It is _not_ safe to assume the first device in the list is the default device.
You can pass in NULL for the playback or capture lists in which case they'll be ignored.
The returned pointers will become invalid upon the next call to this function, or when the context is uninitialized. Do not free the returned pointers.
The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers.
See Also
...
...
@@ -4847,7 +4847,7 @@ from a microphone. Whether or not you should send or receive data from the devic
playback, capture, full-duplex or loopback. (Note that loopback mode is only supported on select backends.) Sending and receiving audio data to and from the
device is done via a callback which is fired by miniaudio at periodic time intervals.
The frequency at which data is delivered to and from a device depends on the size of its period. The size of the period can be defined in terms of PCM frames
The frequency at which data is delivered to and from a device depends on the size of it's period. The size of the period can be defined in terms of PCM frames
or milliseconds, whichever is more convenient. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and
increased risk of glitching due to the more frequent and granular data deliver intervals. The size of a period will depend on your requirements, but
miniaudio's defaults should work fine for most scenarios. If you're building a game you should leave this fairly small, whereas if you're building a simple
...
...
@@ -4921,7 +4921,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c
performanceProfile
A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or
`ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at its default value.
`ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value.
noPreSilencedOutputBuffer
When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of
...
...
@@ -4961,7 +4961,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c
A pointer that will passed to callbacks in pBackendVTable.
resampling.linear.lpfOrder
The linear resampler applies a low-pass filter as part of its processing for anti-aliasing. This setting controls the order of the filter. The higher
The linear resampler applies a low-pass filter as part of it's processing for anti-aliasing. This setting controls the order of the filter. The higher
the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is
`MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`.
...
...
@@ -5211,7 +5211,7 @@ Unsafe. It is not safe to call this inside any callback.
Remarks
-------
You only need to use this function if you want to configure the context differently to its defaults. You should never use this function if you want to manage
You only need to use this function if you want to configure the context differently to it's defaults. You should never use this function if you want to manage
your own context.
See the documentation for `ma_context_init()` for information on the different context configuration options.
...
...
@@ -6233,7 +6233,7 @@ struct ma_decoder
void*pInputCache;/* In input format. Can be null if it's not needed. */
ma_uint64inputCacheCap;/* The capacity of the input cache. */
ma_uint64inputCacheConsumed;/* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
ma_uint64inputCacheRemaining;/* The number of valid frames remaining in the cache. */
ma_uint64inputCacheRemaining;/* The number of valid frames remaining in the cahce. */
ma_allocation_callbacksallocationCallbacks;
union
{
...
...
@@ -6274,7 +6274,7 @@ This is not thread safe without your own synchronization.
/* Base node object for both ma_sound and ma_sound_group. */
typedefstruct
{
ma_node_basebaseNode;/* Must be the first member for compatibility with the ma_node API. */
ma_node_basebaseNode;/* Must be the first member for compatiblity with the ma_node API. */
ma_engine*pEngine;/* A pointer to the engine. Set based on the value from the config. */
ma_uint32sampleRate;/* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */
@@ -5531,7 +5531,7 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
0.97 - builds under c++ (typecasting, don't use 'class' keyword)
0.96 - somehow MY 0.95 was right, but the web one was wrong, so here's my 0.95 rereleased as 0.96, fixes a typo in the clamping code
0.95 - clamping code for 16-bit functions
0.94 - not publicly released
0.94 - not publically released
0.93 - fixed all-zero-floor case (was decoding garbage)
0.92 - fixed a memory leak
0.91 - conditional compiles to omit parts of the API and the infrastructure to support them: STB_VORBIS_NO_PULLDATA_API, STB_VORBIS_NO_PUSHDATA_API, STB_VORBIS_NO_STDIO, STB_VORBIS_NO_INTEGER_CONVERSION