view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
| ma_noise_type_pink |
| ma_noise_type_brownian |
+------------------------+
9. Audio Buffers
================
miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can read from memory that's managed by the application, but
can also handle the memory management for you internally. Memory management is flexible and should support most use cases.
Audio buffers are initialised using the standard configuration system used everywhere in miniaudio:
```c
ma_audio_buffer_config config = ma_audio_buffer_config_init(
format,
channels,
sizeInFrames,
pExistingData,
&allocationCallbacks);
ma_audio_buffer buffer;
result = ma_audio_buffer_init(&config, &buffer);
if (result != MA_SUCCESS) {
// Error.
}
...
ma_audio_buffer_uninit(&buffer);
```
In the example above, the memory pointed to by `pExistingData` will _not_ be copied and is how an application can do self-managed memory allocation. If you
would rather make a copy of the data, use `ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`.
Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure _and_ the raw audio data in a contiguous block of memory. That is,
the raw audio data will be located immediately after the `ma_audio_buffer` structure. To do this, use `ma_audio_buffer_alloc_and_init()`:
```c
ma_audio_buffer_config config = ma_audio_buffer_config_init(
format,
channels,
sizeInFrames,
pExistingData,
&allocationCallbacks);
ma_audio_buffer* pBuffer
result = ma_audio_buffer_alloc_and_init(&config, &pBuffer);
if (result != MA_SUCCESS) {
// Error
}
...
ma_audio_buffer_uninit_and_free(&buffer);
```
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.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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);
MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder);
/*
Retrieves the current position of the read cursor in PCM frames.
*/
MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor);
/*
Retrieves the length of the decoder in PCM frames.
Do not call this on streams of an undefined length, such as internet radio.
If the length is unknown or an error occurs, 0 will be returned.
This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
uses internally.
For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
This function is not thread safe without your own synchronization.
*/
MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder);
/*
Reads PCM frames from the given decoder.
This is not thread safe without your own synchronization.
*/
MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount);
/*
Seeks to a PCM frame based on it's absolute index.
This is not thread safe without your own synchronization.
*/
MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex);
/*
Retrieves the number of frames that can be read before reaching the end.
This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in
particular ensuring you do not call it on streams of an undefined length, such as internet radio.
If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be
returned.
*/
MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames);
/*
Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input,
pConfig should be set to what you want. On output it will be set to what you got.
*/
MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
#endif /* MA_NO_DECODING */
/************************************************************************************************************************************************************
Encoding
========
Encoders do not perform any format conversion for you. If your target format does not support the format, and error will be returned.
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
if (pDevice->usingDefaultSampleRate) {
/* We base the sample rate on the values returned by GetCaps(). */
if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
wf.Format.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate);
} else {
wf.Format.nSamplesPerSec = caps.dwMaxSecondarySampleRate;
}
}
wf.Format.nBlockAlign = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
/*
From MSDN:
The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest
supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer
and compare the result with the format that was requested with the SetFormat method.
*/
hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf);
if (FAILED(hr)) {
ma_device_uninit__dsound(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.", ma_result_from_HRESULT(hr));
}
/* Get the _actual_ properties of the buffer. */
pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", ma_result_from_HRESULT(hr));
}
pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
pDevice->playback.internalChannels = pActualFormat->Format.nChannels;
pDevice->playback.internalSampleRate = pActualFormat->Format.nSamplesPerSec;
/* Get the internal channel map based on the channel mask. */
if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
} else {
ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
}
/* The size of the buffer must be a clean multiple of the period count. */
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pDevice->playback.internalSampleRate);
/*
Meaning of dwFlags (from MSDN):
DSBCAPS_CTRLPOSITIONNOTIFY
The buffer has position notification capability.
DSBCAPS_GLOBALFOCUS
With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to
another application, even if the new application uses DirectSound.
DSBCAPS_GETCURRENTPOSITION2
In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated
sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the
application can get a more accurate play cursor.
*/
MA_ZERO_OBJECT(&descDS);
descDS.dwSize = sizeof(descDS);
descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2;
descDS.dwBufferBytes = periodSizeInFrames * pConfig->periods * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL);
if (FAILED(hr)) {
ma_device_uninit__dsound(pDevice);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", ma_result_from_HRESULT(hr));
}
/* DirectSound should give us a buffer exactly the size we asked for. */
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->playback.internalPeriods = pConfig->periods;
}
(void)pContext;
return MA_SUCCESS;
}
static ma_result ma_device_main_loop__dsound(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_uint32 bpfDeviceCapture = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 bpfDevicePlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
HRESULT hr;
DWORD lockOffsetInBytesCapture;
DWORD lockSizeInBytesCapture;
DWORD mappedSizeInBytesCapture;
DWORD mappedDeviceFramesProcessedCapture;
void* pMappedDeviceBufferCapture;
DWORD lockOffsetInBytesPlayback;
DWORD lockSizeInBytesPlayback;
DWORD mappedSizeInBytesPlayback;
void* pMappedDeviceBufferPlayback;
DWORD prevReadCursorInBytesCapture = 0;
DWORD prevPlayCursorInBytesPlayback = 0;
ma_bool32 physicalPlayCursorLoopFlagPlayback = 0;
DWORD virtualWriteCursorInBytesPlayback = 0;
ma_bool32 virtualWriteCursorLoopFlagPlayback = 0;
ma_bool32 isPlaybackDeviceStarted = MA_FALSE;
ma_uint32 framesWrittenToPlaybackDevice = 0; /* For knowing whether or not the playback device needs to be started. */
ma_uint32 waitTimeInMilliseconds = 1;
MA_ASSERT(pDevice != NULL);
/* The first thing to do is start the capture device. The playback device is only started after the first period is written. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (FAILED(ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING))) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MA_FAILED_TO_START_BACKEND_DEVICE);
}
}
while (ma_device__get_state(pDevice) == MA_STATE_STARTED) {
switch (pDevice->type)
{
case ma_device_type_duplex:
{
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
} else {
/*
The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
do it again from the start.
*/
if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
/* Lock up to the end of the buffer. */
lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
lockSizeInBytesCapture = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
} else {
/* Lock starting from the start of the buffer. */
lockOffsetInBytesCapture = 0;
lockSizeInBytesCapture = physicalReadCursorInBytes;
}
}
if (lockSizeInBytesCapture == 0) {
ma_sleep(waitTimeInMilliseconds);
continue; /* Nothing is available in the capture buffer. */
}
hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
}
/* At this point we have some input data that we need to output. We do not return until every mapped frame of the input data is written to the playback device. */
mappedDeviceFramesProcessedCapture = 0;
for (;;) { /* Keep writing to the playback device. */
ma_uint8 inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 inputFramesInClientFormatCap = sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint8 outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 outputFramesInClientFormatCap = sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
ma_uint32 outputFramesInClientFormatCount;
ma_uint32 outputFramesInClientFormatConsumed = 0;
ma_uint64 clientCapturedFramesToProcess = ma_min(inputFramesInClientFormatCap, outputFramesInClientFormatCap);
ma_uint64 deviceCapturedFramesToProcess = (mappedSizeInBytesCapture / bpfDeviceCapture) - mappedDeviceFramesProcessedCapture;
void* pRunningMappedDeviceBufferCapture = ma_offset_ptr(pMappedDeviceBufferCapture, mappedDeviceFramesProcessedCapture * bpfDeviceCapture);
result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningMappedDeviceBufferCapture, &deviceCapturedFramesToProcess, inputFramesInClientFormat, &clientCapturedFramesToProcess);
if (result != MA_SUCCESS) {
break;
}
outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess;
mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess;
ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess);
/* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */
for (;;) {
ma_uint32 framesWrittenThisIteration;
DWORD physicalPlayCursorInBytes;
DWORD physicalWriteCursorInBytes;
DWORD availableBytesPlayback;
DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */
/* We need the physical play and write cursors. */
if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) {
break;
}
if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
}
prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes;
/* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
/* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
} else {
/* This is an error. */
#ifdef MA_DEBUG_OUTPUT
printf("[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, v...
#endif
availableBytesPlayback = 0;
}
} else {
/* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
} else {
/* This is an error. */
#ifdef MA_DEBUG_OUTPUT
printf("[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, v...
#endif
availableBytesPlayback = 0;
}
}
#ifdef MA_DEBUG_OUTPUT
/*printf("[DirectSound] (Duplex/Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
#endif
/* If there's no room available for writing we need to wait for more. */
if (availableBytesPlayback == 0) {
/* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
if (!isPlaybackDeviceStarted) {
hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
if (FAILED(hr)) {
ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
}
isPlaybackDeviceStarted = MA_TRUE;
} else {
ma_sleep(waitTimeInMilliseconds);
continue;
}
}
/* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */
lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
/* Same loop iteration. Go up to the end of the buffer. */
lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
} else {
/* Different loop iterations. Go up to the physical play cursor. */
lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
}
hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
if (FAILED(hr)) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
break;
}
/*
Experiment: If the playback buffer is being starved, pad it with some silence to get it back in sync. This will cause a glitch, but it may prevent
endless glitching due to it constantly running out of data.
*/
if (isPlaybackDeviceStarted) {
DWORD bytesQueuedForPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - availableBytesPlayback;
if (bytesQueuedForPlayback < (pDevice->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) {
silentPaddingInBytes = (pDevice->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback) - bytesQueuedForPlayback;
if (silentPaddingInBytes > lockSizeInBytesPlayback) {
silentPaddingInBytes = lockSizeInBytesPlayback;
}
#ifdef MA_DEBUG_OUTPUT
printf("[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes);
#endif
}
}
/* At this point we have a buffer for output. */
if (silentPaddingInBytes > 0) {
MA_ZERO_MEMORY(pMappedDeviceBufferPlayback, silentPaddingInBytes);
framesWrittenThisIteration = silentPaddingInBytes/bpfDevicePlayback;
} else {
ma_uint64 convertedFrameCountIn = (outputFramesInClientFormatCount - outputFramesInClientFormatConsumed);
ma_uint64 convertedFrameCountOut = mappedSizeInBytesPlayback/bpfDevicePlayback;
void* pConvertedFramesIn = ma_offset_ptr(outputFramesInClientFormat, outputFramesInClientFormatConsumed * bpfDevicePlayback);
void* pConvertedFramesOut = pMappedDeviceBufferPlayback;
result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesIn, &convertedFrameCountIn, pConvertedFramesOut, &convertedFrameCountOut);
if (result != MA_SUCCESS) {
break;
}
outputFramesInClientFormatConsumed += (ma_uint32)convertedFrameCountOut;
framesWrittenThisIteration = (ma_uint32)convertedFrameCountOut;
}
hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0);
if (FAILED(hr)) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
break;
}
virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfDevicePlayback;
if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback) == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods) {
virtualWriteCursorInBytesPlayback = 0;
virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
}
/*
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
lockSizeInBytesCapture = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
} else {
/* Lock starting from the start of the buffer. */
lockOffsetInBytesCapture = 0;
lockSizeInBytesCapture = physicalReadCursorInBytes;
}
}
#ifdef MA_DEBUG_OUTPUT
/*printf("[DirectSound] (Capture) physicalCaptureCursorInBytes=%d, physicalReadCursorInBytes=%d\n", physicalCaptureCursorInBytes, physicalReadCursorInBytes);*/
/*printf("[DirectSound] (Capture) lockOffsetInBytesCapture=%d, lockSizeInBytesCapture=%d\n", lockOffsetInBytesCapture, lockSizeInBytesCapture);*/
#endif
if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) {
ma_sleep(waitTimeInMilliseconds);
continue; /* Nothing is available in the capture buffer. */
}
hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
}
#ifdef MA_DEBUG_OUTPUT
if (lockSizeInBytesCapture != mappedSizeInBytesCapture) {
printf("[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
}
#endif
ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture);
hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
}
prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture;
if (prevReadCursorInBytesCapture == (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture)) {
prevReadCursorInBytesCapture = 0;
}
} break;
case ma_device_type_playback:
{
DWORD availableBytesPlayback;
DWORD physicalPlayCursorInBytes;
DWORD physicalWriteCursorInBytes;
hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
if (FAILED(hr)) {
break;
}
if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
}
prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes;
/* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
/* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
} else {
/* This is an error. */
#ifdef MA_DEBUG_OUTPUT
printf("[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCurs...
#endif
availableBytesPlayback = 0;
}
} else {
/* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
} else {
/* This is an error. */
#ifdef MA_DEBUG_OUTPUT
printf("[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCurs...
#endif
availableBytesPlayback = 0;
}
}
#ifdef MA_DEBUG_OUTPUT
/*printf("[DirectSound] (Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
#endif
/* If there's no room available for writing we need to wait for more. */
if (availableBytesPlayback < pDevice->playback.internalPeriodSizeInFrames) {
/* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) {
hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
}
isPlaybackDeviceStarted = MA_TRUE;
} else {
ma_sleep(waitTimeInMilliseconds);
continue;
}
}
/* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */
lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
/* Same loop iteration. Go up to the end of the buffer. */
lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
} else {
/* Different loop iterations. Go up to the physical play cursor. */
lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
}
hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
if (FAILED(hr)) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
break;
}
/* At this point we have a buffer for output. */
ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfDevicePlayback), pMappedDeviceBufferPlayback);
hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0);
if (FAILED(hr)) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
break;
}
virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback;
if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) {
virtualWriteCursorInBytesPlayback = 0;
virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
}
/*
We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds
a bit of a buffer to prevent the playback buffer from getting starved.
*/
framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfDevicePlayback;
if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) {
hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
}
isPlaybackDeviceStarted = MA_TRUE;
}
} break;
default: return MA_INVALID_ARGS; /* Invalid device type. */
}
if (result != MA_SUCCESS) {
return result;
}
}
/* Getting here means the device is being stopped. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
/* The playback device should be drained before stopping. All we do is wait until the available bytes is equal to the size of the buffer. */
if (isPlaybackDeviceStarted) {
for (;;) {
DWORD availableBytesPlayback = 0;
DWORD physicalPlayCursorInBytes;
DWORD physicalWriteCursorInBytes;
hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
if (FAILED(hr)) {
break;
}
if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
}
prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes;
if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
/* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
} else {
break;
}
} else {
/* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
} else {
break;
}
}
if (availableBytesPlayback >= (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback)) {
break;
}
ma_sleep(waitTimeInMilliseconds);
}
}
hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
if (FAILED(hr)) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
}
ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0);
}
return MA_SUCCESS;
}
static ma_result ma_context_uninit__dsound(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_dsound);
ma_dlclose(pContext, pContext->dsound.hDSoundDLL);
return MA_SUCCESS;
}
static ma_result ma_context_init__dsound(const ma_context_config* pConfig, ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
(void)pConfig;
pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll");
if (pContext->dsound.hDSoundDLL == NULL) {
return MA_API_NOT_FOUND;
}
pContext->dsound.DirectSoundCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate");
pContext->dsound.DirectSoundEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA");
pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate");
pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA");
pContext->onUninit = ma_context_uninit__dsound;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__dsound;
pContext->onEnumDevices = ma_context_enumerate_devices__dsound;
pContext->onGetDeviceInfo = ma_context_get_device_info__dsound;
pContext->onDeviceInit = ma_device_init__dsound;
pContext->onDeviceUninit = ma_device_uninit__dsound;
pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceMainLoop. */
pContext->onDeviceStop = NULL; /* Not used. Stopped in onDeviceMainLoop. */
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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);
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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;
}
MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex)
{
if (pAudioBuffer == NULL) {
return MA_INVALID_ARGS;
}
if (frameIndex > pAudioBuffer->sizeInFrames) {
return MA_INVALID_ARGS;
}
pAudioBuffer->cursor = (size_t)frameIndex;
return MA_SUCCESS;
}
MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount)
{
ma_uint64 framesAvailable;
ma_uint64 frameCount = 0;
if (ppFramesOut != NULL) {
*ppFramesOut = NULL; /* Safety. */
}
if (pFrameCount != NULL) {
frameCount = *pFrameCount;
*pFrameCount = 0; /* Safety. */
}
if (pAudioBuffer == NULL || ppFramesOut == NULL || pFrameCount == NULL) {
return MA_INVALID_ARGS;
}
framesAvailable = pAudioBuffer->sizeInFrames - pAudioBuffer->cursor;
if (frameCount > framesAvailable) {
frameCount = framesAvailable;
}
*ppFramesOut = ma_offset_ptr(pAudioBuffer->pData, pAudioBuffer->cursor * ma_get_bytes_per_frame(pAudioBuffer->format, pAudioBuffer->channels));
*pFrameCount = frameCount;
return MA_SUCCESS;
}
MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount)
{
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;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
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;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_mp3(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_vorbis(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_w(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_wav_w(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_flac_w(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_mp3_w(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
{
return ma_decoder_init_vfs_vorbis_w(NULL, pFilePath, pConfig, pDecoder);
}
MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder)
{
if (pDecoder == NULL) {
return MA_INVALID_ARGS;
}
if (pDecoder->onUninit) {
pDecoder->onUninit(pDecoder);
}
if (pDecoder->onRead == ma_decoder__on_read_vfs) {
if (pDecoder->backend.vfs.pVFS == NULL) {
ma_default_vfs_close(NULL, pDecoder->backend.vfs.file);
} else {
ma_vfs_close(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file);
}
}
ma_data_converter_uninit(&pDecoder->converter);
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 {
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
}
return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount);
}
#endif /* MA_NO_ENCODING */
/**************************************************************************************************************************************************************
Generation
**************************************************************************************************************************************************************/
#ifndef MA_NO_GENERATION
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)
{
ma_waveform_config config;
MA_ZERO_OBJECT(&config);
config.format = format;
config.channels = channels;
config.sampleRate = sampleRate;
config.type = type;
config.amplitude = amplitude;
config.frequency = frequency;
return config;
}
static ma_result ma_waveform__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_uint64 framesRead = ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount);
if (pFramesRead != NULL) {
*pFramesRead = framesRead;
}
if (framesRead < frameCount) {
return MA_AT_END;
}
return MA_SUCCESS;
}
static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
return ma_waveform_seek_to_pcm_frame((ma_waveform*)pDataSource, frameIndex);
}
static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
{
ma_waveform* pWaveform = (ma_waveform*)pDataSource;
*pFormat = pWaveform->config.format;
*pChannels = pWaveform->config.channels;
*pSampleRate = pWaveform->config.sampleRate;
return MA_SUCCESS;
}
static ma_result ma_waveform__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
ma_waveform* pWaveform = (ma_waveform*)pDataSource;
*pCursor = (ma_uint64)(pWaveform->time / pWaveform->advance);
return MA_SUCCESS;
}
MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform)
{
if (pWaveform == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pWaveform);
pWaveform->ds.onRead = ma_waveform__data_source_on_read;
pWaveform->ds.onSeek = ma_waveform__data_source_on_seek;
pWaveform->ds.onGetDataFormat = ma_waveform__data_source_on_get_data_format;
pWaveform->ds.onGetCursor = ma_waveform__data_source_on_get_cursor;
pWaveform->ds.onGetLength = NULL; /* Intentionally set to NULL since there's no notion of a length in waveforms. */
pWaveform->config = *pConfig;
pWaveform->advance = 1.0 / pWaveform->config.sampleRate;
pWaveform->time = 0;
return MA_SUCCESS;
}
MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude)
{
if (pWaveform == NULL) {
return MA_INVALID_ARGS;
}
pWaveform->config.amplitude = amplitude;
return MA_SUCCESS;
}
MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency)
{
if (pWaveform == NULL) {
return MA_INVALID_ARGS;
}
pWaveform->config.frequency = frequency;
return MA_SUCCESS;
}
MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate)
{
if (pWaveform == NULL) {
return MA_INVALID_ARGS;
}
pWaveform->advance = 1.0 / sampleRate;
return MA_SUCCESS;
}
static float ma_waveform_sine_f32(double time, double frequency, double amplitude)
{
return (float)(ma_sin(MA_TAU_D * time * frequency) * amplitude);
}
static ma_int16 ma_waveform_sine_s16(double time, double frequency, double amplitude)
{
return ma_pcm_sample_f32_to_s16(ma_waveform_sine_f32(time, frequency, amplitude));
}
static float ma_waveform_square_f32(double time, double frequency, double amplitude)
{
double t = time * frequency;
double f = t - (ma_int64)t;
double r;
if (f < 0.5) {
r = amplitude;
} else {
r = -amplitude;
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
config.seed = MA_DEFAULT_LCG_SEED;
}
return config;
}
static ma_result ma_noise__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_uint64 framesRead = ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount);
if (pFramesRead != NULL) {
*pFramesRead = framesRead;
}
if (framesRead < frameCount) {
return MA_AT_END;
}
return MA_SUCCESS;
}
static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
/* No-op. Just pretend to be successful. */
(void)pDataSource;
(void)frameIndex;
return MA_SUCCESS;
}
static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
{
ma_noise* pNoise = (ma_noise*)pDataSource;
*pFormat = pNoise->config.format;
*pChannels = pNoise->config.channels;
*pSampleRate = 0; /* There is no notion of sample rate with noise generation. */
return MA_SUCCESS;
}
MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise)
{
if (pNoise == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pNoise);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
pNoise->ds.onRead = ma_noise__data_source_on_read;
pNoise->ds.onSeek = ma_noise__data_source_on_seek; /* <-- No-op for noise. */
pNoise->ds.onGetDataFormat = ma_noise__data_source_on_get_data_format;
pNoise->ds.onGetCursor = NULL; /* No notion of a cursor for noise. */
pNoise->ds.onGetLength = NULL; /* No notion of a length for noise. */
pNoise->config = *pConfig;
ma_lcg_seed(&pNoise->lcg, pConfig->seed);
if (pNoise->config.type == ma_noise_type_pink) {
ma_uint32 iChannel;
for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
pNoise->state.pink.accumulation[iChannel] = 0;
pNoise->state.pink.counter[iChannel] = 1;
}
}
if (pNoise->config.type == ma_noise_type_brownian) {
ma_uint32 iChannel;
for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
pNoise->state.brownian.accumulation[iChannel] = 0;
}
}
return MA_SUCCESS;
}
static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise)
{
return (float)(ma_lcg_rand_f64(&pNoise->lcg) * pNoise->config.amplitude);
}
static MA_INLINE ma_int16 ma_noise_s16_white(ma_noise* pNoise)
{
return ma_pcm_sample_f32_to_s16(ma_noise_f32_white(pNoise));
}
static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
{
ma_uint64 iFrame;
ma_uint32 iChannel;
if (pNoise->config.format == ma_format_f32) {
float* pFramesOutF32 = (float*)pFramesOut;
if (pNoise->config.duplicateChannels) {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_noise_f32_white(pNoise);
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s;
}
}
} else {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_white(pNoise);
}
}
}
} else if (pNoise->config.format == ma_format_s16) {
ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
if (pNoise->config.duplicateChannels) {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
ma_int16 s = ma_noise_s16_white(pNoise);
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s;
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
if (pNoise->config.duplicateChannels) {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_noise_f32_brownian(pNoise, 0);
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s;
}
}
} else {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel);
}
}
}
} else if (pNoise->config.format == ma_format_s16) {
ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
if (pNoise->config.duplicateChannels) {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
ma_int16 s = ma_noise_s16_brownian(pNoise, 0);
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s;
}
}
} else {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel);
}
}
}
} else {
ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
ma_uint32 bpf = bps * pNoise->config.channels;
if (pNoise->config.duplicateChannels) {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_noise_f32_brownian(pNoise, 0);
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
}
}
} else {
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
float s = ma_noise_f32_brownian(pNoise, iChannel);
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
}
}
}
}
return frameCount;
}
MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
{
if (pNoise == NULL) {
return 0;
}
/* The output buffer is allowed to be NULL. Since we aren't tracking cursors or anything we can just do nothing and pretend to be successful. */
if (pFramesOut == NULL) {
return frameCount;
}
if (pNoise->config.type == ma_noise_type_white) {
return ma_noise_read_pcm_frames__white(pNoise, pFramesOut, frameCount);
}
if (pNoise->config.type == ma_noise_type_pink) {
return ma_noise_read_pcm_frames__pink(pNoise, pFramesOut, frameCount);
}
if (pNoise->config.type == ma_noise_type_brownian) {
return ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount);
}
/* Should never get here. */
MA_ASSERT(MA_FALSE);
return 0;
}
#endif /* MA_NO_GENERATION */
/**************************************************************************************************************************************************************
***************************************************************************************************************************************************************
Auto Generated
==============
All code below is auto-generated from a tool. This mostly consists of decoding backend implementations such as dr_wav, dr_flac, etc. If you find a bug in the
code below please report the bug to the respective repository for the relevant project (probably dr_libs).
***************************************************************************************************************************************************************
**************************************************************************************************************************************************************/
#if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING))
#if !defined(DR_WAV_IMPLEMENTATION) && !defined(DRWAV_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
/* dr_wav_c begin */
#ifndef dr_wav_c
#define dr_wav_c
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifndef DR_WAV_NO_STDIO
#include <stdio.h>
#include <wchar.h>
#endif
#ifndef DRWAV_ASSERT
#include <assert.h>
#define DRWAV_ASSERT(expression) assert(expression)
#endif
#ifndef DRWAV_MALLOC
#define DRWAV_MALLOC(sz) malloc((sz))
#endif
#ifndef DRWAV_REALLOC
#define DRWAV_REALLOC(p, sz) realloc((p), (sz))
#endif
#ifndef DRWAV_FREE
#define DRWAV_FREE(p) free((p))
#endif
#ifndef DRWAV_COPY_MEMORY
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
{
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;
}
} else {
drwav_uint8 chunkSizeBytes[8];
drwav_uint8 wave[16];
if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
return DRWAV_FALSE;
}
if (drwav__bytes_to_u64(chunkSizeBytes) < 80) {
return DRWAV_FALSE;
}
if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
return DRWAV_FALSE;
}
if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) {
return DRWAV_FALSE;
}
}
if (pWav->container == drwav_container_rf64) {
drwav_uint8 sizeBytes[8];
drwav_uint64 bytesRemainingInChunk;
drwav_chunk_header header;
drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
if (result != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
if (!drwav__fourcc_equal(header.id.fourcc, "ds64")) {
return DRWAV_FALSE;
}
bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
cursor += 8;
if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
dataChunkSize = drwav__bytes_to_u64(sizeBytes);
if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
sampleCountFromFactChunk = drwav__bytes_to_u64(sizeBytes);
if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
return DRWAV_FALSE;
}
cursor += bytesRemainingInChunk;
}
if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
return DRWAV_FALSE;
}
if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) ||
(fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) ||
(fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
fmt.blockAlign == 0) {
return DRWAV_FALSE;
}
translatedFormatTag = fmt.formatTag;
if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0);
}
foundDataChunk = DRWAV_FALSE;
for (;;)
{
drwav_chunk_header header;
drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
if (result != DRWAV_SUCCESS) {
if (!foundDataChunk) {
return DRWAV_FALSE;
} else {
break;
}
}
if (!sequential && onChunk != NULL) {
drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
if (callbackBytesRead > 0) {
if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
return DRWAV_FALSE;
}
}
}
if (!foundDataChunk) {
pWav->dataChunkDataPos = cursor;
}
chunkSize = header.sizeInBytes;
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
if (drwav__fourcc_equal(header.id.fourcc, "data")) {
foundDataChunk = DRWAV_TRUE;
if (pWav->container != drwav_container_rf64) {
dataChunkSize = chunkSize;
}
}
} else {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
foundDataChunk = DRWAV_TRUE;
dataChunkSize = chunkSize;
}
}
if (foundDataChunk && sequential) {
break;
}
if (pWav->container == drwav_container_riff) {
if (drwav__fourcc_equal(header.id.fourcc, "fact")) {
drwav_uint32 sampleCount;
if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
return DRWAV_FALSE;
}
chunkSize -= 4;
if (!foundDataChunk) {
pWav->dataChunkDataPos = cursor;
}
if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
sampleCountFromFactChunk = sampleCount;
} else {
sampleCountFromFactChunk = 0;
}
}
} else if (pWav->container == drwav_container_w64) {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
return DRWAV_FALSE;
}
chunkSize -= 8;
if (!foundDataChunk) {
pWav->dataChunkDataPos = cursor;
}
}
} else if (pWav->container == drwav_container_rf64) {
}
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
if (drwav__fourcc_equal(header.id.fourcc, "smpl")) {
drwav_uint8 smplHeaderData[36];
if (chunkSize >= sizeof(smplHeaderData)) {
drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor);
chunkSize -= bytesJustRead;
if (bytesJustRead == sizeof(smplHeaderData)) {
drwav_uint32 iLoop;
pWav->smpl.manufacturer = drwav__bytes_to_u32(smplHeaderData+0);
pWav->smpl.product = drwav__bytes_to_u32(smplHeaderData+4);
pWav->smpl.samplePeriod = drwav__bytes_to_u32(smplHeaderData+8);
pWav->smpl.midiUnityNotes = drwav__bytes_to_u32(smplHeaderData+12);
pWav->smpl.midiPitchFraction = drwav__bytes_to_u32(smplHeaderData+16);
pWav->smpl.smpteFormat = drwav__bytes_to_u32(smplHeaderData+20);
pWav->smpl.smpteOffset = drwav__bytes_to_u32(smplHeaderData+24);
pWav->smpl.numSampleLoops = drwav__bytes_to_u32(smplHeaderData+28);
pWav->smpl.samplerData = drwav__bytes_to_u32(smplHeaderData+32);
for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) {
drwav_uint8 smplLoopData[24];
bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor);
chunkSize -= bytesJustRead;
if (bytesJustRead == sizeof(smplLoopData)) {
pWav->smpl.loops[iLoop].cuePointId = drwav__bytes_to_u32(smplLoopData+0);
pWav->smpl.loops[iLoop].type = drwav__bytes_to_u32(smplLoopData+4);
pWav->smpl.loops[iLoop].start = drwav__bytes_to_u32(smplLoopData+8);
pWav->smpl.loops[iLoop].end = drwav__bytes_to_u32(smplLoopData+12);
pWav->smpl.loops[iLoop].fraction = drwav__bytes_to_u32(smplLoopData+16);
pWav->smpl.loops[iLoop].playCount = drwav__bytes_to_u32(smplLoopData+20);
} else {
break;
}
}
}
} else {
}
}
} else {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) {
}
}
chunkSize += header.paddingSize;
if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
break;
}
cursor += chunkSize;
if (!foundDataChunk) {
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);
}
share/public_html/static/music_inc/src/miniaudio.h view on Meta::CPAN
- The ma_backend enums have been rearranged to priority order. The rationale for this is to simplify automatic backend selection and to make it easier to see
the priority. If you're a binding maintainer you will need to update.
- ma_dsp has been renamed to ma_pcm_converter. The rationale for this change is that I'm expecting "ma_dsp" to conflict with some future planned high-level
APIs.
- For functions that take a pointer/count combo, such as ma_decoder_read_pcm_frames(), the parameter order has changed so that the pointer comes before the
count. The rationale for this is to keep it consistent with things like memcpy().
Miscellaneous Changes
---------------------
The following miscellaneous changes have also been made.
- The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the record, this is one of the nicest
audio APIs out there, just behind the BSD audio APIs).
- The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL.
- The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio was not explicitly
supported. These are no longer needed and have therefore been removed.
- Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an exclusive mode device, or an
error. The rationale for this change is to give the client more control over how to handle cases when the desired shared mode is unavailable.
- A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb" operates on PCM frames.
- The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but removes the attribution
requirement. The rationale for this is to support countries that don't recognize public domain.
*/
/*
REVISION HISTORY
================
v0.10.21 - 2020-10-30
- Add ma_is_backend_enabled() and ma_get_enabled_backends() for retrieving enabled backends at run-time.
- WASAPI: Fix a copy and paste bug relating to loopback mode.
- Core Audio: Fix a bug when using multiple contexts.
- Core Audio: Fix a compilation warning.
- Core Audio: Improvements to sample rate selection.
- Core Audio: Improvements to format/channels/rate selection when requesting defaults.
- Core Audio: Add notes regarding the Apple notarization process.
- Fix some bugs due to null pointer dereferences.
v0.10.20 - 2020-10-06
- Fix build errors with UWP.
- Minor documentation updates.
v0.10.19 - 2020-09-22
- WASAPI: Return an error when exclusive mode is requested, but the native format is not supported by miniaudio.
- Fix a bug where ma_decoder_seek_to_pcm_frames() never returns MA_SUCCESS even though it was successful.
- Store the sample rate in the `ma_lpf` and `ma_hpf` structures.
v0.10.18 - 2020-08-30
- Fix build errors with VC6.
- Fix a bug in channel converter for s32 format.
- Change channel converter configs to use the default channel map instead of a blank channel map when no channel map is specified when initializing the
config. This fixes an issue where the optimized mono expansion path would never get used.
- Use a more appropriate default format for FLAC decoders. This will now use ma_format_s16 when the FLAC is encoded as 16-bit.
- Update FLAC decoder.
- Update links to point to the new repository location (https://github.com/mackron/miniaudio).
v0.10.17 - 2020-08-28
- Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set.
- Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed.
- Fix compilation error on Android.
- Core Audio: Fix a bug with full-duplex mode.
- Add ma_decoder_get_cursor_in_pcm_frames().
- Update WAV codec.
v0.10.16 - 2020-08-14
- WASAPI: Fix a potential crash due to using an uninitialized variable.
- OpenSL: Enable runtime linking.
- OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time.
- iOS: Improvements to device enumeration.
- Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL.
- Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work.
- Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled.
- Fix some compilation warnings when no decoders are enabled.
- Add ma_audio_buffer_get_available_frames().
- Add ma_decoder_get_available_frames().
- Add sample rate to ma_data_source_get_data_format().
- Change volume APIs to take 64-bit frame counts.
- Updates to documentation.
v0.10.15 - 2020-07-15
- Fix a bug when converting bit-masked channel maps to miniaudio channel maps. This affects the WASAPI and OpenSL backends.
v0.10.14 - 2020-07-14
- Fix compilation errors on Android.
- Fix compilation errors with -march=armv6.
- Updates to the documentation.
v0.10.13 - 2020-07-11
- Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS.
- Fix compilation error on Emscripten.
- Silence some unused function warnings.
- Increase the default buffer size on the Web Audio backend. This fixes glitching issues on some browsers.
- Bring FLAC decoder up-to-date with dr_flac.
- Bring MP3 decoder up-to-date with dr_mp3.
v0.10.12 - 2020-07-04
- Fix compilation errors on the iOS build.
v0.10.11 - 2020-06-28
- Fix some bugs with device tracking on Core Audio.
- Updates to documentation.
v0.10.10 - 2020-06-26
- Add include guard for the implementation section.
- Mark ma_device_sink_info_callback() as static.
- Fix compilation errors with MA_NO_DECODING and MA_NO_ENCODING.
- Fix compilation errors with MA_NO_DEVICE_IO
v0.10.9 - 2020-06-24
- Amalgamation of dr_wav, dr_flac and dr_mp3. With this change, including the header section of these libraries before the implementation of miniaudio is no
longer required. Decoding of WAV, FLAC and MP3 should be supported seamlessly without any additional libraries. Decoders can be excluded from the build
with the following options:
- MA_NO_WAV
- MA_NO_FLAC
- MA_NO_MP3
If you get errors about multiple definitions you need to either enable the options above, move the implementation of dr_wav, dr_flac and/or dr_mp3 to before
the implementation of miniaudio, or update dr_wav, dr_flac and/or dr_mp3.
- Changes to the internal atomics library. This has been replaced with c89atomic.h which is embedded within this file.
- Fix a bug when a decoding backend reports configurations outside the limits of miniaudio's decoder abstraction.
- Fix the UWP build.
- Fix the Core Audio build.
- Fix the -std=c89 build on GCC.