From 26d9ba6712eebbd8bfeba2996bcfa72bbed1b923 Mon Sep 17 00:00:00 2001 From: "J.C. Moyer" Date: Sun, 5 May 2024 03:34:09 -0400 Subject: [PATCH] Work in frames instead of samples --- src/main_frontend.cpp | 23 +++++++--------- src/ringbuffer.h | 64 ++++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/src/main_frontend.cpp b/src/main_frontend.cpp index 1f432338..9a228ebc 100644 --- a/src/main_frontend.cpp +++ b/src/main_frontend.cpp @@ -134,37 +134,34 @@ void FE_ReceiveSample(void* userdata, int *sample) { fe_emu_instance_t& fe = *(fe_emu_instance_t*)userdata; sample[0] >>= 15; - if (sample[0] > INT16_MAX) - sample[0] = INT16_MAX; - else if (sample[0] < INT16_MIN) - sample[0] = INT16_MIN; sample[1] >>= 15; - if (sample[1] > INT16_MAX) - sample[1] = INT16_MAX; - else if (sample[1] < INT16_MIN) - sample[1] = INT16_MIN; - RB_Write(fe.sample_buffer, sample[0], sample[1]); + + audio_frame_t frame; + frame.left = (int16_t)clamp(sample[0], INT16_MIN, INT16_MAX); + frame.right = (int16_t)clamp(sample[1], INT16_MIN, INT16_MAX); + + RB_Write(fe.sample_buffer, frame); } void FE_AudioCallback(void* userdata, Uint8* stream, int len) { frontend_t& frontend = *(frontend_t*)userdata; - const size_t num_samples = len / sizeof(int16_t); + const size_t num_frames = len / sizeof(audio_frame_t); memset(stream, 0, len); - size_t renderable_count = num_samples; + size_t renderable_count = num_frames; for (size_t i = 0; i < frontend.instances_in_use; ++i) { renderable_count = min( renderable_count, - RB_ReadableSampleCount(frontend.instances[i].sample_buffer) + RB_ReadableFrameCount(frontend.instances[i].sample_buffer) ); } for (size_t i = 0; i < frontend.instances_in_use; ++i) { - RB_ReadMix(frontend.instances[i].sample_buffer, (int16_t*)stream, renderable_count); + RB_ReadMix(frontend.instances[i].sample_buffer, (audio_frame_t*)stream, renderable_count); } } diff --git a/src/ringbuffer.h b/src/ringbuffer.h index 53bcbbd8..a51b9beb 100644 --- a/src/ringbuffer.h +++ b/src/ringbuffer.h @@ -38,12 +38,14 @@ #include #include "math_util.h" -const int RB_CHANNEL_COUNT = 2; +struct audio_frame_t { + int16_t left; + int16_t right; +}; struct ringbuffer_t { - int16_t* samples; + audio_frame_t* frames; size_t frame_count; - size_t sample_count; size_t read_head; size_t write_head; bool oversampling; @@ -51,13 +53,12 @@ struct ringbuffer_t { inline bool RB_Init(ringbuffer_t& rb, size_t frame_count) { - rb.samples = (int16_t*)calloc(RB_CHANNEL_COUNT * frame_count, sizeof(int16_t)); - if (!rb.samples) + rb.frames = (audio_frame_t*)calloc(frame_count, sizeof(audio_frame_t)); + if (!rb.frames) { return false; } rb.frame_count = frame_count; - rb.sample_count = RB_CHANNEL_COUNT * frame_count; rb.read_head = 0; rb.write_head = 0; rb.oversampling = false; @@ -66,17 +67,13 @@ inline bool RB_Init(ringbuffer_t& rb, size_t frame_count) inline void RB_Free(ringbuffer_t& rb) { - free(rb.samples); + free(rb.frames); } inline void RB_SetOversamplingEnabled(ringbuffer_t& rb, bool enabled) { rb.oversampling = enabled; if (rb.oversampling) - { - rb.write_head &= ~3; - } - else { rb.write_head &= ~1; } @@ -86,22 +83,21 @@ inline bool RB_IsFull(ringbuffer_t& rb) { if (rb.oversampling) { - return ((rb.write_head + 2 * RB_CHANNEL_COUNT) % rb.sample_count) == rb.read_head; + return ((rb.write_head + 2) % rb.frame_count) == rb.read_head; } else { - return ((rb.write_head + 1 * RB_CHANNEL_COUNT) % rb.sample_count) == rb.read_head; + return ((rb.write_head + 1) % rb.frame_count) == rb.read_head; } } -inline void RB_Write(ringbuffer_t& rb, int16_t left, int16_t right) +inline void RB_Write(ringbuffer_t& rb, const audio_frame_t& frame) { - rb.samples[rb.write_head + 0] = left; - rb.samples[rb.write_head + 1] = right; - rb.write_head = (rb.write_head + RB_CHANNEL_COUNT) % rb.sample_count; + rb.frames[rb.write_head] = frame; + rb.write_head = (rb.write_head + 1) % rb.frame_count; } -inline size_t RB_ReadableSampleCount(ringbuffer_t& rb) +inline size_t RB_ReadableFrameCount(ringbuffer_t& rb) { if (rb.read_head <= rb.write_head) { @@ -109,40 +105,40 @@ inline size_t RB_ReadableSampleCount(ringbuffer_t& rb) } else { - return rb.sample_count - (rb.read_head - rb.write_head); + return rb.frame_count - (rb.read_head - rb.write_head); } } -// Reads up to `sample_count` samples and returns the number of samples -// actually read. -inline size_t RB_Read(ringbuffer_t& rb, int16_t* dest, size_t sample_count) +// Reads up to `frame_count` frames and returns the number of frames actually +// read. +inline size_t RB_Read(ringbuffer_t& rb, audio_frame_t* dest, size_t frame_count) { - size_t have_count = RB_ReadableSampleCount(rb); - size_t read_count = sample_count < have_count ? sample_count : have_count; + const size_t have_count = RB_ReadableFrameCount(rb); + const size_t read_count = min(have_count, frame_count); size_t read_head = rb.read_head; // TODO make this one or two memcpys for (size_t i = 0; i < read_count; ++i) { - *dest = rb.samples[read_head]; + *dest = rb.frames[read_head]; ++dest; - read_head = (read_head + 1) % rb.sample_count; + read_head = (read_head + 1) % rb.frame_count; } rb.read_head = read_head; return read_count; } -// Reads up to `sample_count` samples and returns the number of samples -// actually read. Mixes samples into dest by adding and clipping. -inline size_t RB_ReadMix(ringbuffer_t& rb, int16_t* dest, size_t sample_count) +// Reads up to `frame_count` frames and returns the number of frames actually +// read. Mixes samples into dest by adding and clipping. +inline size_t RB_ReadMix(ringbuffer_t& rb, audio_frame_t* dest, size_t frame_count) { - size_t have_count = RB_ReadableSampleCount(rb); - size_t read_count = sample_count < have_count ? sample_count : have_count; + const size_t have_count = RB_ReadableFrameCount(rb); + const size_t read_count = min(have_count, frame_count); size_t read_head = rb.read_head; for (size_t i = 0; i < read_count; ++i) { - *dest = saturating_add(*dest, rb.samples[read_head]); - ++dest; - read_head = (read_head + 1) % rb.sample_count; + dest[i].left = saturating_add(dest[i].left, rb.frames[read_head].left); + dest[i].right = saturating_add(dest[i].right, rb.frames[read_head].right); + read_head = (read_head + 1) % rb.frame_count; } rb.read_head = read_head; return read_count;