mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Add support for using ma_pcm_rb as a data source.
This commit is contained in:
@@ -2,6 +2,7 @@ v0.11.12 - TBD
|
|||||||
=====================
|
=====================
|
||||||
* Fix some pedantic warnings when compiling with GCC.
|
* Fix some pedantic warnings when compiling with GCC.
|
||||||
* Fix some crashes with the WAV decoder when loading an invalid file.
|
* Fix some crashes with the WAV decoder when loading an invalid file.
|
||||||
|
* Add support for using `ma_pcm_rb` as a data source.
|
||||||
* Silence some C89 compatibility warnings with Clang.
|
* Silence some C89 compatibility warnings with Clang.
|
||||||
* The `pBytesRead` parameter of the VFS onRead callback is now pre-initialized to zero.
|
* The `pBytesRead` parameter of the VFS onRead callback is now pre-initialized to zero.
|
||||||
|
|
||||||
|
|||||||
+329
-191
@@ -5732,6 +5732,197 @@ MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_forma
|
|||||||
MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig);
|
MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig);
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************************************************************************************
|
||||||
|
|
||||||
|
Data Source
|
||||||
|
|
||||||
|
************************************************************************************************************************************************************/
|
||||||
|
typedef void ma_data_source;
|
||||||
|
|
||||||
|
#define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 0x00000001
|
||||||
|
|
||||||
|
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 (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
|
||||||
|
ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor);
|
||||||
|
ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength);
|
||||||
|
ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping);
|
||||||
|
ma_uint32 flags;
|
||||||
|
} ma_data_source_vtable;
|
||||||
|
|
||||||
|
typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const ma_data_source_vtable* vtable;
|
||||||
|
} ma_data_source_config;
|
||||||
|
|
||||||
|
MA_API ma_data_source_config ma_data_source_config_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const ma_data_source_vtable* vtable;
|
||||||
|
ma_uint64 rangeBegInFrames;
|
||||||
|
ma_uint64 rangeEndInFrames; /* Set to -1 for unranged (default). */
|
||||||
|
ma_uint64 loopBegInFrames; /* Relative to rangeBegInFrames. */
|
||||||
|
ma_uint64 loopEndInFrames; /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */
|
||||||
|
ma_data_source* pCurrent; /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */
|
||||||
|
ma_data_source* pNext; /* When set to NULL, onGetNext will be used. */
|
||||||
|
ma_data_source_get_next_proc onGetNext; /* Will be used when pNext is NULL. If both are NULL, no next will be used. */
|
||||||
|
MA_ATOMIC(4, ma_bool32) isLooping;
|
||||||
|
} ma_data_source_base;
|
||||||
|
|
||||||
|
MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource);
|
||||||
|
MA_API void ma_data_source_uninit(ma_data_source* pDataSource);
|
||||||
|
MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* 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); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */
|
||||||
|
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_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
|
||||||
|
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. */
|
||||||
|
MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor);
|
||||||
|
MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength);
|
||||||
|
MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping);
|
||||||
|
MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source* pDataSource);
|
||||||
|
MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames);
|
||||||
|
MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames);
|
||||||
|
MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames);
|
||||||
|
MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames);
|
||||||
|
MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource);
|
||||||
|
MA_API ma_data_source* ma_data_source_get_current(const ma_data_source* pDataSource);
|
||||||
|
MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource);
|
||||||
|
MA_API ma_data_source* ma_data_source_get_next(const ma_data_source* pDataSource);
|
||||||
|
MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext);
|
||||||
|
MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source* pDataSource);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ma_data_source_base ds;
|
||||||
|
ma_format format;
|
||||||
|
ma_uint32 channels;
|
||||||
|
ma_uint32 sampleRate;
|
||||||
|
ma_uint64 cursor;
|
||||||
|
ma_uint64 sizeInFrames;
|
||||||
|
const void* pData;
|
||||||
|
} ma_audio_buffer_ref;
|
||||||
|
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef);
|
||||||
|
MA_API void ma_audio_buffer_ref_uninit(ma_audio_buffer_ref* pAudioBufferRef);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames);
|
||||||
|
MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
|
||||||
|
MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pCursor);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pLength);
|
||||||
|
MA_API ma_result ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ma_format format;
|
||||||
|
ma_uint32 channels;
|
||||||
|
ma_uint32 sampleRate;
|
||||||
|
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_audio_buffer_ref ref;
|
||||||
|
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_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer);
|
||||||
|
MA_API ma_result ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pCursor);
|
||||||
|
MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pLength);
|
||||||
|
MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Paged Audio Buffer
|
||||||
|
==================
|
||||||
|
A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It
|
||||||
|
can be used for cases where audio data is streamed in asynchronously while allowing data to be read
|
||||||
|
at the same time.
|
||||||
|
|
||||||
|
This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across
|
||||||
|
simultaneously across different threads, however only one thread at a time can append, and only one
|
||||||
|
thread at a time can read and seek.
|
||||||
|
*/
|
||||||
|
typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page;
|
||||||
|
struct ma_paged_audio_buffer_page
|
||||||
|
{
|
||||||
|
MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pNext;
|
||||||
|
ma_uint64 sizeInFrames;
|
||||||
|
ma_uint8 pAudioData[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ma_format format;
|
||||||
|
ma_uint32 channels;
|
||||||
|
ma_paged_audio_buffer_page head; /* Dummy head for the lock-free algorithm. Always has a size of 0. */
|
||||||
|
MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pTail; /* Never null. Initially set to &head. */
|
||||||
|
} ma_paged_audio_buffer_data;
|
||||||
|
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData);
|
||||||
|
MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData);
|
||||||
|
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ma_paged_audio_buffer_data* pData; /* Must not be null. */
|
||||||
|
} ma_paged_audio_buffer_config;
|
||||||
|
|
||||||
|
MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ma_data_source_base ds;
|
||||||
|
ma_paged_audio_buffer_data* pData; /* Audio data is read from here. Cannot be null. */
|
||||||
|
ma_paged_audio_buffer_page* pCurrent;
|
||||||
|
ma_uint64 relativeCursor; /* Relative to the current page. */
|
||||||
|
ma_uint64 absoluteCursor;
|
||||||
|
} ma_paged_audio_buffer;
|
||||||
|
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer);
|
||||||
|
MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Returns MA_AT_END if no more pages available. */
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor);
|
||||||
|
MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************************************************************************************************
|
/************************************************************************************************************************************************************
|
||||||
|
|
||||||
Ring Buffer
|
Ring Buffer
|
||||||
@@ -5771,9 +5962,11 @@ MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pB
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
ma_data_source_base ds;
|
||||||
ma_rb rb;
|
ma_rb rb;
|
||||||
ma_format format;
|
ma_format format;
|
||||||
ma_uint32 channels;
|
ma_uint32 channels;
|
||||||
|
ma_uint32 sampleRate; /* Not required for the ring buffer itself, but useful for associating the data with some sample rate, particularly for data sources. */
|
||||||
} ma_pcm_rb;
|
} ma_pcm_rb;
|
||||||
|
|
||||||
MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB);
|
MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB);
|
||||||
@@ -5793,6 +5986,10 @@ MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB);
|
|||||||
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB);
|
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB);
|
||||||
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex);
|
MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex);
|
||||||
MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
|
MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
|
||||||
|
MA_API ma_format ma_pcm_rb_get_format(const ma_pcm_rb* pRB);
|
||||||
|
MA_API ma_uint32 ma_pcm_rb_get_channels(const ma_pcm_rb* pRB);
|
||||||
|
MA_API ma_uint32 ma_pcm_rb_get_sample_rate(const ma_pcm_rb* pRB);
|
||||||
|
MA_API void ma_pcm_rb_set_sample_rate(ma_pcm_rb* pRB, ma_uint32 sampleRate);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -9553,195 +9750,6 @@ This will run on an optimized path when the volume is equal to 1.
|
|||||||
MA_API ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume);
|
MA_API ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume);
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************************************
|
|
||||||
|
|
||||||
Data Source
|
|
||||||
|
|
||||||
**************************************************************************************************/
|
|
||||||
typedef void ma_data_source;
|
|
||||||
|
|
||||||
#define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT 0x00000001
|
|
||||||
|
|
||||||
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 (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
|
|
||||||
ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor);
|
|
||||||
ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength);
|
|
||||||
ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping);
|
|
||||||
ma_uint32 flags;
|
|
||||||
} ma_data_source_vtable;
|
|
||||||
|
|
||||||
typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource);
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const ma_data_source_vtable* vtable;
|
|
||||||
} ma_data_source_config;
|
|
||||||
|
|
||||||
MA_API ma_data_source_config ma_data_source_config_init(void);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const ma_data_source_vtable* vtable;
|
|
||||||
ma_uint64 rangeBegInFrames;
|
|
||||||
ma_uint64 rangeEndInFrames; /* Set to -1 for unranged (default). */
|
|
||||||
ma_uint64 loopBegInFrames; /* Relative to rangeBegInFrames. */
|
|
||||||
ma_uint64 loopEndInFrames; /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */
|
|
||||||
ma_data_source* pCurrent; /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */
|
|
||||||
ma_data_source* pNext; /* When set to NULL, onGetNext will be used. */
|
|
||||||
ma_data_source_get_next_proc onGetNext; /* Will be used when pNext is NULL. If both are NULL, no next will be used. */
|
|
||||||
MA_ATOMIC(4, ma_bool32) isLooping;
|
|
||||||
} ma_data_source_base;
|
|
||||||
|
|
||||||
MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource);
|
|
||||||
MA_API void ma_data_source_uninit(ma_data_source* pDataSource);
|
|
||||||
MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* 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); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */
|
|
||||||
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_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
|
|
||||||
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. */
|
|
||||||
MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor);
|
|
||||||
MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength);
|
|
||||||
MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping);
|
|
||||||
MA_API ma_bool32 ma_data_source_is_looping(const ma_data_source* pDataSource);
|
|
||||||
MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames);
|
|
||||||
MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames);
|
|
||||||
MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames);
|
|
||||||
MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames);
|
|
||||||
MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource);
|
|
||||||
MA_API ma_data_source* ma_data_source_get_current(const ma_data_source* pDataSource);
|
|
||||||
MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource);
|
|
||||||
MA_API ma_data_source* ma_data_source_get_next(const ma_data_source* pDataSource);
|
|
||||||
MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext);
|
|
||||||
MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(const ma_data_source* pDataSource);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
ma_data_source_base ds;
|
|
||||||
ma_format format;
|
|
||||||
ma_uint32 channels;
|
|
||||||
ma_uint32 sampleRate;
|
|
||||||
ma_uint64 cursor;
|
|
||||||
ma_uint64 sizeInFrames;
|
|
||||||
const void* pData;
|
|
||||||
} ma_audio_buffer_ref;
|
|
||||||
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef);
|
|
||||||
MA_API void ma_audio_buffer_ref_uninit(ma_audio_buffer_ref* pAudioBufferRef);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames);
|
|
||||||
MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount); /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
|
|
||||||
MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pCursor);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pLength);
|
|
||||||
MA_API ma_result ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
ma_format format;
|
|
||||||
ma_uint32 channels;
|
|
||||||
ma_uint32 sampleRate;
|
|
||||||
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_audio_buffer_ref ref;
|
|
||||||
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_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer);
|
|
||||||
MA_API ma_result ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pCursor);
|
|
||||||
MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pLength);
|
|
||||||
MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Paged Audio Buffer
|
|
||||||
==================
|
|
||||||
A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It
|
|
||||||
can be used for cases where audio data is streamed in asynchronously while allowing data to be read
|
|
||||||
at the same time.
|
|
||||||
|
|
||||||
This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across
|
|
||||||
simultaneously across different threads, however only one thread at a time can append, and only one
|
|
||||||
thread at a time can read and seek.
|
|
||||||
*/
|
|
||||||
typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page;
|
|
||||||
struct ma_paged_audio_buffer_page
|
|
||||||
{
|
|
||||||
MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pNext;
|
|
||||||
ma_uint64 sizeInFrames;
|
|
||||||
ma_uint8 pAudioData[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
ma_format format;
|
|
||||||
ma_uint32 channels;
|
|
||||||
ma_paged_audio_buffer_page head; /* Dummy head for the lock-free algorithm. Always has a size of 0. */
|
|
||||||
MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pTail; /* Never null. Initially set to &head. */
|
|
||||||
} ma_paged_audio_buffer_data;
|
|
||||||
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData);
|
|
||||||
MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks);
|
|
||||||
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData);
|
|
||||||
MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
ma_paged_audio_buffer_data* pData; /* Must not be null. */
|
|
||||||
} ma_paged_audio_buffer_config;
|
|
||||||
|
|
||||||
MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
ma_data_source_base ds;
|
|
||||||
ma_paged_audio_buffer_data* pData; /* Audio data is read from here. Cannot be null. */
|
|
||||||
ma_paged_audio_buffer_page* pCurrent;
|
|
||||||
ma_uint64 relativeCursor; /* Relative to the current page. */
|
|
||||||
ma_uint64 absoluteCursor;
|
|
||||||
} ma_paged_audio_buffer;
|
|
||||||
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer);
|
|
||||||
MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Returns MA_AT_END if no more pages available. */
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor);
|
|
||||||
MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************************************************************************************************
|
/************************************************************************************************************************************************************
|
||||||
@@ -56388,6 +56396,86 @@ MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pB
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Add stubs for each of the functions in ma_data_source_vtable. Named ma_pcm_rb_data_source__on_read, etc. */
|
||||||
|
static ma_result ma_pcm_rb_data_source__on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
|
||||||
|
{
|
||||||
|
/* Since there's no notion of an end, we don't ever want to return MA_AT_END here. But it is possible to return 0. */
|
||||||
|
ma_pcm_rb* pRB = (ma_pcm_rb*)pDataSource;
|
||||||
|
ma_result result;
|
||||||
|
ma_uint64 totalFramesRead;
|
||||||
|
|
||||||
|
MA_ASSERT(pRB != NULL);
|
||||||
|
|
||||||
|
/* We need to run this in a loop since the ring buffer itself may loop. */
|
||||||
|
totalFramesRead = 0;
|
||||||
|
while (totalFramesRead < frameCount) {
|
||||||
|
void* pMappedBuffer;
|
||||||
|
ma_uint32 mappedFrameCount;
|
||||||
|
ma_uint64 framesToRead = frameCount - totalFramesRead;
|
||||||
|
if (framesToRead > 0xFFFFFFFF) {
|
||||||
|
framesToRead = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
mappedFrameCount = (ma_uint32)framesToRead;
|
||||||
|
result = ma_pcm_rb_acquire_read(pRB, &mappedFrameCount, &pMappedBuffer);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedFrameCount == 0) {
|
||||||
|
break; /* <-- End of ring buffer. */
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, pRB->format, pRB->channels), pMappedBuffer, mappedFrameCount, pRB->format, pRB->channels);
|
||||||
|
|
||||||
|
result = ma_pcm_rb_commit_read(pRB, mappedFrameCount);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalFramesRead += mappedFrameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pFramesRead = totalFramesRead;
|
||||||
|
return MA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ma_result ma_pcm_rb_data_source__on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
|
||||||
|
{
|
||||||
|
ma_pcm_rb* pRB = (ma_pcm_rb*)pDataSource;
|
||||||
|
MA_ASSERT(pRB != NULL);
|
||||||
|
|
||||||
|
if (pFormat != NULL) {
|
||||||
|
*pFormat = pRB->format;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pChannels != NULL) {
|
||||||
|
*pChannels = pRB->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSampleRate != NULL) {
|
||||||
|
*pSampleRate = pRB->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just assume the default channel map. */
|
||||||
|
if (pChannelMap != NULL) {
|
||||||
|
ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pRB->channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ma_data_source_vtable ma_gRBDataSourceVTable =
|
||||||
|
{
|
||||||
|
ma_pcm_rb_data_source__on_read,
|
||||||
|
NULL, /* onSeek */
|
||||||
|
ma_pcm_rb_data_source__on_get_data_format,
|
||||||
|
NULL, /* onGetCursor */
|
||||||
|
NULL, /* onGetLength */
|
||||||
|
NULL, /* onSetLooping */
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB)
|
static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB)
|
||||||
{
|
{
|
||||||
MA_ASSERT(pRB != NULL);
|
MA_ASSERT(pRB != NULL);
|
||||||
@@ -56416,8 +56504,21 @@ MA_API ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pRB->format = format;
|
pRB->format = format;
|
||||||
pRB->channels = channels;
|
pRB->channels = channels;
|
||||||
|
pRB->sampleRate = 0; /* The sample rate is not passed in as a parameter. */
|
||||||
|
|
||||||
|
/* The PCM ring buffer is a data source. We need to get that set up as well. */
|
||||||
|
{
|
||||||
|
ma_data_source_config dataSourceConfig = ma_data_source_config_init();
|
||||||
|
dataSourceConfig.vtable = &ma_gRBDataSourceVTable;
|
||||||
|
|
||||||
|
result = ma_data_source_init(&dataSourceConfig, &pRB->ds);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
ma_rb_uninit(&pRB->rb);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -56433,6 +56534,7 @@ MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ma_data_source_uninit(&pRB->ds);
|
||||||
ma_rb_uninit(&pRB->rb);
|
ma_rb_uninit(&pRB->rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56584,6 +56686,42 @@ MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferInde
|
|||||||
return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer);
|
return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MA_API ma_format ma_pcm_rb_get_format(const ma_pcm_rb* pRB)
|
||||||
|
{
|
||||||
|
if (pRB == NULL) {
|
||||||
|
return ma_format_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRB->format;
|
||||||
|
}
|
||||||
|
|
||||||
|
MA_API ma_uint32 ma_pcm_rb_get_channels(const ma_pcm_rb* pRB)
|
||||||
|
{
|
||||||
|
if (pRB == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRB->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
MA_API ma_uint32 ma_pcm_rb_get_sample_rate(const ma_pcm_rb* pRB)
|
||||||
|
{
|
||||||
|
if (pRB == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRB->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
MA_API void ma_pcm_rb_set_sample_rate(ma_pcm_rb* pRB, ma_uint32 sampleRate)
|
||||||
|
{
|
||||||
|
if (pRB == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRB->sampleRate = sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB)
|
MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB)
|
||||||
|
|||||||
Reference in New Issue
Block a user