From d1f34cd5db3cc11a8ec5633b68a7460afef87797 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 27 Jan 2026 17:44:52 +1000 Subject: [PATCH] Update the audio ring buffer to use the standard config/init pattern. This makes it consistent with everything else in the library. --- examples/duplex_effect.c | 5 +- examples/hilo_interop.c | 5 +- miniaudio.h | 153 ++++++++++++++++++++++++--------------- 3 files changed, 102 insertions(+), 61 deletions(-) diff --git a/examples/duplex_effect.c b/examples/duplex_effect.c index 405223d4..17e65257 100644 --- a/examples/duplex_effect.c +++ b/examples/duplex_effect.c @@ -53,6 +53,7 @@ int main(int argc, char** argv) ma_data_source_node_config sourceNodeConfig; ma_data_source_node_config exciteNodeConfig; ma_waveform_config waveformConfig; + ma_audio_ring_buffer_config ringBufferConfig; deviceConfig = ma_device_config_init(ma_device_type_duplex); 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. */ - 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) { printf("Failed to initialize audio buffer for source."); goto done2; diff --git a/examples/hilo_interop.c b/examples/hilo_interop.c index c1d7a94b..dfa18ac1 100644 --- a/examples/hilo_interop.c +++ b/examples/hilo_interop.c @@ -35,6 +35,7 @@ int main(int argc, char** argv) { ma_result result; 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 @@ -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. */ - 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) { printf("Failed to initialize the ring buffer."); return -1; diff --git a/miniaudio.h b/miniaudio.h index 8371b822..0db1d43d 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -3568,25 +3568,30 @@ you will want to use. To initialize a ring buffer, do something like the followi ```c 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) { // Error } ``` -The `ma_audio_ring_buffer_init()` function takes the sample format, channel count and sample rate -as parameters because it's the PCM variant of the ring buffer API. The sample rate is not used by -the ring buffer internally and can be set to 0, but it is provided for the purpose of the data -source implementation. +The `ma_audio_ring_buffer_init()` follows the same config/init pattern used throughout miniaudio. +The sample rate is not used by the ring buffer internally and can be set to 0, but it is provided +for the purpose of the data source implementation. 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 void* pBuffer = malloc(BUFFER_SIZE_IN_FRAMES * bytesPerFrame * 2); // <-- The 2x is important. - ma_audio_ring_buffer rb; - ma_audio_ring_Buffer_init_ex(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES, 0, pBuffer, &rb); + rbConfig = ma_audio_ring_buffer_config_init(FORMAT, CHANNELS, SAMPLE_RATE, BUFFER_SIZE_IN_FRAMES); + 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 @@ -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: ```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: @@ -6284,6 +6295,20 @@ MA_API ma_uint32 ma_ring_buffer_capacity(const ma_ring_buffer* pRingBuffer); /* 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 { ma_data_source_base ds; @@ -6296,8 +6321,7 @@ typedef struct ma_audio_ring_buffer ma_allocation_callbacks allocationCallbacks; } 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(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 capacityInFrames, const ma_allocation_callbacks* pAllocationCallbacks, 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 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 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; 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; @@ -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_data_source_config dataSourceConfig; ma_uint32 bpf; + ma_bool32 isOwnerOfBuffer = MA_FALSE; + void* pBuffer; if (pRingBuffer == NULL) { 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); - if (capacityInFrames == 0) { + if (pConfig == NULL) { 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) { 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; } + /* 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. */ - ma_ring_buffer_init(capacityInFrames, bpf, flags, pBuffer, &pRingBuffer->rb); - pRingBuffer->format = format; - pRingBuffer->channels = channels; - pRingBuffer->sampleRate = sampleRate; - pRingBuffer->pBuffer = pBuffer; - - return MA_SUCCESS; -} - -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; + ma_ring_buffer_init(pConfig->sizeInFrames, bpf, pConfig->flags, pBuffer, &pRingBuffer->rb); + pRingBuffer->format = pConfig->format; + pRingBuffer->channels = pConfig->channels; + pRingBuffer->sampleRate = pConfig->sampleRate; + pRingBuffer->isOwnerOfBuffer = isOwnerOfBuffer; + pRingBuffer->pBuffer = pBuffer; + ma_allocation_callbacks_init_copy(&pRingBuffer->allocationCallbacks, pConfig->pAllocationCallbacks); 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_uint32 sizeInFrames; + ma_audio_ring_buffer_config ringBufferConfig; sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 3); if (sizeInFrames == 0) { 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) { return result; }