You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.8 KiB

#include "AudioRing.h"
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
struct MusubiRing {
float *data;
uint32_t capacity; // frames, power of two
uint32_t mask;
uint32_t channels;
_Atomic uint64_t writeIndex; // frames written in total
_Atomic uint64_t readIndex; // frames read in total
};
static uint32_t next_power_of_two(uint32_t value) {
uint32_t result = 1;
while (result < value) result <<= 1;
return result;
}
MusubiRing *musubi_ring_create(uint32_t capacityFrames, uint32_t channels) {
if (capacityFrames == 0 || channels == 0) return NULL;
MusubiRing *ring = calloc(1, sizeof(MusubiRing));
if (!ring) return NULL;
ring->capacity = next_power_of_two(capacityFrames);
ring->mask = ring->capacity - 1;
ring->channels = channels;
ring->data = calloc((size_t)ring->capacity * channels, sizeof(float));
if (!ring->data) { free(ring); return NULL; }
atomic_init(&ring->writeIndex, 0);
atomic_init(&ring->readIndex, 0);
return ring;
}
void musubi_ring_destroy(MusubiRing *ring) {
if (!ring) return;
free(ring->data);
free(ring);
}
uint32_t musubi_ring_channels(const MusubiRing *ring) { return ring->channels; }
uint32_t musubi_ring_capacity(const MusubiRing *ring) { return ring->capacity; }
uint32_t musubi_ring_available(const MusubiRing *ring) {
uint64_t w = atomic_load_explicit(&((MusubiRing *)ring)->writeIndex, memory_order_acquire);
uint64_t r = atomic_load_explicit(&((MusubiRing *)ring)->readIndex, memory_order_acquire);
return (uint32_t)(w - r);
}
// Copies `frames` frames between the ring (starting at frame index `start`) and a linear buffer.
static void copy_frames(MusubiRing *ring, uint64_t start, float *linear, uint32_t frames, int toRing) {
uint32_t offset = (uint32_t)(start & ring->mask);
uint32_t first = ring->capacity - offset;
if (first > frames) first = frames;
size_t frameBytes = sizeof(float) * ring->channels;
float *slot = ring->data + (size_t)offset * ring->channels;
if (toRing) {
memcpy(slot, linear, first * frameBytes);
memcpy(ring->data, linear + (size_t)first * ring->channels, (frames - first) * frameBytes);
} else {
memcpy(linear, slot, first * frameBytes);
memcpy(linear + (size_t)first * ring->channels, ring->data, (frames - first) * frameBytes);
}
}
uint32_t musubi_ring_write(MusubiRing *ring, const float *interleaved, uint32_t frames) {
uint64_t w = atomic_load_explicit(&ring->writeIndex, memory_order_relaxed);
uint64_t r = atomic_load_explicit(&ring->readIndex, memory_order_acquire);
uint32_t space = ring->capacity - (uint32_t)(w - r);
if (frames > space) frames = space;
if (frames == 0) return 0;
copy_frames(ring, w, (float *)interleaved, frames, 1);
atomic_store_explicit(&ring->writeIndex, w + frames, memory_order_release);
return frames;
}
uint32_t musubi_ring_read(MusubiRing *ring, float *interleaved, uint32_t frames) {
uint64_t r = atomic_load_explicit(&ring->readIndex, memory_order_relaxed);
uint64_t w = atomic_load_explicit(&ring->writeIndex, memory_order_acquire);
uint32_t available = (uint32_t)(w - r);
if (frames > available) frames = available;
if (frames == 0) return 0;
copy_frames(ring, r, interleaved, frames, 0);
atomic_store_explicit(&ring->readIndex, r + frames, memory_order_release);
return frames;
}
uint32_t musubi_ring_skip(MusubiRing *ring, uint32_t frames) {
uint64_t r = atomic_load_explicit(&ring->readIndex, memory_order_relaxed);
uint64_t w = atomic_load_explicit(&ring->writeIndex, memory_order_acquire);
uint32_t available = (uint32_t)(w - r);
if (frames > available) frames = available;
atomic_store_explicit(&ring->readIndex, r + frames, memory_order_release);
return frames;
}

Powered by TurnKey Linux.