Update the audio ring buffer to use the standard config/init pattern.

This makes it consistent with everything else in the library.
This commit is contained in:
David Reid
2026-01-27 17:44:52 +10:00
parent 75b3f7dddc
commit d1f34cd5db
3 changed files with 102 additions and 61 deletions
+4 -1
View File
@@ -53,6 +53,7 @@ int main(int argc, char** argv)
ma_data_source_node_config sourceNodeConfig; ma_data_source_node_config sourceNodeConfig;
ma_data_source_node_config exciteNodeConfig; ma_data_source_node_config exciteNodeConfig;
ma_waveform_config waveformConfig; ma_waveform_config waveformConfig;
ma_audio_ring_buffer_config ringBufferConfig;
deviceConfig = ma_device_config_init(ma_device_type_duplex); deviceConfig = ma_device_config_init(ma_device_type_duplex);
deviceConfig.capture.pDeviceID = NULL; deviceConfig.capture.pDeviceID = NULL;
@@ -115,7 +116,9 @@ int main(int argc, char** argv)
/* Excite/modulator. Attached to input bus 1 of the vocoder node. */ /* Excite/modulator. Attached to input bus 1 of the vocoder node. */
result = ma_audio_ring_buffer_init(device.capture.format, device.capture.channels, device.sampleRate, device.capture.internalPeriodSizeInFrames * 3, NULL, &g_exciteData); ringBufferConfig = ma_audio_ring_buffer_config_init(device.capture.format, device.capture.channels, device.sampleRate, device.capture.internalPeriodSizeInFrames * 3);
result = ma_audio_ring_buffer_init(&ringBufferConfig, &g_exciteData);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
printf("Failed to initialize audio buffer for source."); printf("Failed to initialize audio buffer for source.");
goto done2; goto done2;
+4 -1
View File
@@ -35,6 +35,7 @@ int main(int argc, char** argv)
{ {
ma_result result; ma_result result;
ma_device_config deviceConfig; ma_device_config deviceConfig;
ma_audio_ring_buffer_config ringBufferConfig;
/* /*
The first thing we'll do is set up the capture side. There are two parts to this. The first is The first thing we'll do is set up the capture side. There are two parts to this. The first is
@@ -59,7 +60,9 @@ int main(int argc, char** argv)
} }
/* Initialize the ring buffer. Make sure the sample rate is set so the engine can resample it if necessary. */ /* Initialize the ring buffer. Make sure the sample rate is set so the engine can resample it if necessary. */
result = ma_audio_ring_buffer_init(device.capture.format, device.capture.channels, device.sampleRate, device.capture.internalPeriodSizeInFrames * 3, NULL, &rb); ringBufferConfig = ma_audio_ring_buffer_config_init(device.capture.format, device.capture.channels, device.sampleRate, device.capture.internalPeriodSizeInFrames * 3);
result = ma_audio_ring_buffer_init(&ringBufferConfig, &rb);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
printf("Failed to initialize the ring buffer."); printf("Failed to initialize the ring buffer.");
return -1; return -1;
+94 -59
View File
@@ -3568,25 +3568,30 @@ you will want to use. To initialize a ring buffer, do something like the followi
```c ```c
ma_audio_ring_buffer rb; ma_audio_ring_buffer rb;
ma_result result = ma_audio_ring_buffer_init(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES, NULL, &rb); ma_audio_ring_buffer_config rbConfig;
rbConfig = ma_audio_ring_buffer_config_init(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES);
ma_result result = ma_audio_ring_buffer_init(&rbConfig, &rb);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
// Error // Error
} }
``` ```
The `ma_audio_ring_buffer_init()` function takes the sample format, channel count and sample rate The `ma_audio_ring_buffer_init()` follows the same config/init pattern used throughout miniaudio.
as parameters because it's the PCM variant of the ring buffer API. The sample rate is not used by The sample rate is not used by the ring buffer internally and can be set to 0, but it is provided
the ring buffer internally and can be set to 0, but it is provided for the purpose of the data for the purpose of the data source implementation.
source implementation.
You can allocate your own underlying buffer to act as the backing store in which case you can You can allocate your own underlying buffer to act as the backing store in which case you can
initialize it like this: initialize specify it in the config:
```c ```c
void* pBuffer = malloc(BUFFER_SIZE_IN_FRAMES * bytesPerFrame * 2); // <-- The 2x is important. void* pBuffer = malloc(BUFFER_SIZE_IN_FRAMES * bytesPerFrame * 2); // <-- The 2x is important.
ma_audio_ring_buffer rb; rbConfig = ma_audio_ring_buffer_config_init(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES);
ma_audio_ring_Buffer_init_ex(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES, 0, pBuffer, &rb); rbConfig.pBuffer = pBuffer;
ma_audio_ring_Buffer_init(&rbConfig, &rb);
``` ```
The size of the buffer must be 2 times the capacity. It is possible for you to use a mirrored The size of the buffer must be 2 times the capacity. It is possible for you to use a mirrored
@@ -3594,7 +3599,13 @@ buffer where the second half of the buffer maps to the same physical memory as t
this case you can specify the `MA_RING_BUFFER_FLAG_MIRRORED` flag: this case you can specify the `MA_RING_BUFFER_FLAG_MIRRORED` flag:
```c ```c
ma_audio_ring_buffer_init_ex(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES, MA_RING_BUFFER_FLAG_MIRRORED, pBuffer, &rb); void* pBuffer = ...; // <-- Your own OS-specific allocation routine goes here. It must have 2x the addressable space as the the capacity.
rbConfig = ma_audio_ring_buffer_config_init(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES);
rbConfig.flags = MA_RING_BUFFER_FLAG_MIRRORED;
rbConfig.pBuffer = pBuffer;
ma_audio_ring_buffer_init(&rbConfig, &rb);
``` ```
To read and write data you map and unmap a pointer. For writing, you can do something like this: To read and write data you map and unmap a pointer. For writing, you can do something like this:
@@ -6284,6 +6295,20 @@ MA_API ma_uint32 ma_ring_buffer_capacity(const ma_ring_buffer* pRingBuffer);
/* END ma_ring_buffer.h */ /* END ma_ring_buffer.h */
typedef struct ma_audio_ring_buffer_config
{
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate; /* Can be zero. Not used for the actual function of the ring buffer. Stored for the purpose of the data source abstraction. */
ma_uint32 sizeInFrames; /* The capacity of the ring buffer in frames. */
ma_uint32 flags;
void* pBuffer; /* Can be null in which case it'll be allocated internally. */
const ma_allocation_callbacks* pAllocationCallbacks;
} ma_audio_ring_buffer_config;
MA_API ma_audio_ring_buffer_config ma_audio_ring_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames);
typedef struct ma_audio_ring_buffer typedef struct ma_audio_ring_buffer
{ {
ma_data_source_base ds; ma_data_source_base ds;
@@ -6296,8 +6321,7 @@ typedef struct ma_audio_ring_buffer
ma_allocation_callbacks allocationCallbacks; ma_allocation_callbacks allocationCallbacks;
} ma_audio_ring_buffer; } ma_audio_ring_buffer;
MA_API ma_result ma_audio_ring_buffer_init_ex(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, ma_uint32 flags, void* pBuffer, ma_audio_ring_buffer* pRingBuffer); MA_API ma_result ma_audio_ring_buffer_init(const ma_audio_ring_buffer_config* pConfig, ma_audio_ring_buffer* pRingBuffer);
MA_API ma_result ma_audio_ring_buffer_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_audio_ring_buffer* pRingBuffer);
MA_API void ma_audio_ring_buffer_uninit(ma_audio_ring_buffer* pRingBuffer); MA_API void ma_audio_ring_buffer_uninit(ma_audio_ring_buffer* pRingBuffer);
MA_API ma_uint32 ma_audio_ring_buffer_map_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint32 frameCount, void** ppMappedBuffer); /* Returns the number of frames actually mapped. */ MA_API ma_uint32 ma_audio_ring_buffer_map_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint32 frameCount, void** ppMappedBuffer); /* Returns the number of frames actually mapped. */
MA_API void ma_audio_ring_buffer_unmap_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint32 frameCount); MA_API void ma_audio_ring_buffer_unmap_produce(ma_audio_ring_buffer* pRingBuffer, ma_uint32 frameCount);
@@ -32474,7 +32498,10 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
pStreamState->rbSizeInFrames = (ma_uint32)time.size; pStreamState->rbSizeInFrames = (ma_uint32)time.size;
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_SINGLE_THREADED) { if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_SINGLE_THREADED) {
ma_audio_ring_buffer_init(pStreamState->format, pStreamState->channels, pStreamState->sampleRate, pStreamState->rbSizeInFrames, ma_device_get_allocation_callbacks(pDeviceStatePipeWire->pDevice), &pStreamState->rb); ma_audio_ring_buffer_config ringBufferConfig = ma_audio_ring_buffer_config_init(pStreamState->format, pStreamState->channels, pStreamState->sampleRate, pStreamState->rbSizeInFrames);
ringBufferConfig.pAllocationCallbacks = ma_device_get_allocation_callbacks(pDeviceStatePipeWire->pDevice);
ma_audio_ring_buffer_init(&ringBufferConfig, &pStreamState->rb);
} }
pStreamState->initStatus |= MA_PIPEWIRE_INIT_STATUS_HAS_LATENCY; pStreamState->initStatus |= MA_PIPEWIRE_INIT_STATUS_HAS_LATENCY;
@@ -63666,11 +63693,28 @@ static ma_data_source_vtable ma_gDataSourceVTable_AudioRingBuffer =
}; };
MA_API ma_result ma_audio_ring_buffer_init_ex(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, ma_uint32 flags, void* pBuffer, ma_audio_ring_buffer* pRingBuffer) MA_API ma_audio_ring_buffer_config ma_audio_ring_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames)
{
ma_audio_ring_buffer_config config;
MA_ZERO_OBJECT(&config);
config.format = format;
config.channels = channels;
config.sampleRate = sampleRate;
config.sizeInFrames = sizeInFrames;
config.flags = 0;
config.pBuffer = NULL;
return config;
}
MA_API ma_result ma_audio_ring_buffer_init(const ma_audio_ring_buffer_config* pConfig, ma_audio_ring_buffer* pRingBuffer)
{ {
ma_result result; ma_result result;
ma_data_source_config dataSourceConfig; ma_data_source_config dataSourceConfig;
ma_uint32 bpf; ma_uint32 bpf;
ma_bool32 isOwnerOfBuffer = MA_FALSE;
void* pBuffer;
if (pRingBuffer == NULL) { if (pRingBuffer == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
@@ -63678,11 +63722,15 @@ MA_API ma_result ma_audio_ring_buffer_init_ex(ma_format format, ma_uint32 channe
MA_ZERO_OBJECT(pRingBuffer); MA_ZERO_OBJECT(pRingBuffer);
if (capacityInFrames == 0) { if (pConfig == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
bpf = ma_get_bytes_per_frame(format, channels); if (pConfig->format == ma_format_unknown || pConfig->channels == 0 || pConfig->sizeInFrames == 0) {
return MA_INVALID_ARGS;
}
bpf = ma_get_bytes_per_frame(pConfig->format, pConfig->channels);
if (bpf == 0) { if (bpf == 0) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
@@ -63696,50 +63744,33 @@ MA_API ma_result ma_audio_ring_buffer_init_ex(ma_format format, ma_uint32 channe
return result; return result;
} }
/* Allocate a buffer if necessary. */
if (pConfig->pBuffer == NULL) {
size_t bufferSizeInBytes;
bufferSizeInBytes = pConfig->sizeInFrames * bpf * 2; /* Buffer must 2x the capacity. */
MA_ASSERT(bufferSizeInBytes != 0);
pBuffer = ma_malloc(bufferSizeInBytes, pConfig->pAllocationCallbacks);
if (pBuffer == NULL) {
ma_data_source_uninit(&pRingBuffer->ds);
return MA_OUT_OF_MEMORY;
}
isOwnerOfBuffer = MA_TRUE;
} else {
pBuffer = pConfig->pBuffer;
isOwnerOfBuffer = MA_FALSE;
}
/* Now for the ring buffer. */ /* Now for the ring buffer. */
ma_ring_buffer_init(capacityInFrames, bpf, flags, pBuffer, &pRingBuffer->rb); ma_ring_buffer_init(pConfig->sizeInFrames, bpf, pConfig->flags, pBuffer, &pRingBuffer->rb);
pRingBuffer->format = format; pRingBuffer->format = pConfig->format;
pRingBuffer->channels = channels; pRingBuffer->channels = pConfig->channels;
pRingBuffer->sampleRate = sampleRate; pRingBuffer->sampleRate = pConfig->sampleRate;
pRingBuffer->pBuffer = pBuffer; pRingBuffer->isOwnerOfBuffer = isOwnerOfBuffer;
pRingBuffer->pBuffer = pBuffer;
return MA_SUCCESS; ma_allocation_callbacks_init_copy(&pRingBuffer->allocationCallbacks, pConfig->pAllocationCallbacks);
}
MA_API ma_result ma_audio_ring_buffer_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_audio_ring_buffer* pRingBuffer)
{
ma_result result;
ma_uint32 bpf;
void* pBuffer;
if (pRingBuffer == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pRingBuffer);
if (capacityInFrames == 0) {
return MA_INVALID_ARGS;
}
bpf = ma_get_bytes_per_frame(format, channels);
if (bpf == 0) {
return MA_INVALID_ARGS;
}
pBuffer = ma_malloc(capacityInFrames * bpf * 2, pAllocationCallbacks);
if (pBuffer == NULL) {
return MA_OUT_OF_MEMORY;
}
result = ma_audio_ring_buffer_init_ex(format, channels, sampleRate, capacityInFrames, 0, pBuffer, pRingBuffer);
if (result != MA_SUCCESS) {
ma_free(pBuffer, pAllocationCallbacks);
return result;
}
ma_allocation_callbacks_init_copy(&pRingBuffer->allocationCallbacks, pAllocationCallbacks);
pRingBuffer->isOwnerOfBuffer = MA_TRUE;
return MA_SUCCESS; return MA_SUCCESS;
} }
@@ -63907,13 +63938,17 @@ MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureCha
{ {
ma_result result; ma_result result;
ma_uint32 sizeInFrames; ma_uint32 sizeInFrames;
ma_audio_ring_buffer_config ringBufferConfig;
sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 3); sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 3);
if (sizeInFrames == 0) { if (sizeInFrames == 0) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
result = ma_audio_ring_buffer_init(captureFormat, captureChannels, sampleRate, sizeInFrames, pAllocationCallbacks, &pRB->rb); ringBufferConfig = ma_audio_ring_buffer_config_init(captureFormat, captureChannels, sampleRate, sizeInFrames);
ringBufferConfig.pAllocationCallbacks = pAllocationCallbacks;
result = ma_audio_ring_buffer_init(&ringBufferConfig, &pRB->rb);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }