From 9c868c5ecc3e183615a4e3e5a2445f858026dec5 Mon Sep 17 00:00:00 2001
From: Miro Kropacek <[EMAIL REDACTED]>
Date: Thu, 24 Sep 2026 23:25:54 +1000
Subject: [PATCH] atari:audio: fix adaptive DMA buffer sizing
Before this change each refill called the application callback max_buf
times at once, and max_buf (1 to 8 chunks of spec.samples) is adjusted
on every refill based on the number of updates (num_upd) and interrupts
(num_its) counted since the previous one.
The comparisons meant to detect "too many interrupts per update" and
"too many updates per interrupt" shifted the wrong operand, so the
conditions overlapped: the buffer doubled whenever num_upd < 4 * num_its
and halved otherwise. There was no state in which the size stayed the
same, so at any frame rate between the clamps it alternated between two
sizes on every refill.
Change the rule to:
- increase latency only when more than one buffer played since the last
refill, i.e. the hardware replayed stale data,
- decrease it only after several consecutive refills with at least 4
updates per buffer,
- otherwise keep the current size.
Also start with a single chunk instead of the maximum of 8. Previously
every application began with large refills (8 chunks each) and needed
several seconds to shrink to its steady size; now the buffer grows only
when the application actually cannot keep up.
---
src/audio/mint/SDL_mintaudio.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/src/audio/mint/SDL_mintaudio.c b/src/audio/mint/SDL_mintaudio.c
index 3c245d73..a0510907 100644
--- a/src/audio/mint/SDL_mintaudio.c
+++ b/src/audio/mint/SDL_mintaudio.c
@@ -43,11 +43,17 @@
#define MAX_DMA_BUF 8
+/* Minimum number of updates per buffer, and number of consecutive buffers
+ meeting it, before the latency is decreased */
+#define MIN_UPD_PER_BUF 4
+#define MIN_IDLE_BUFS 4
+
SDL_AudioDevice *SDL_MintAudio_device;
static int SDL_MintAudio_num_upd; /* Number of calls to update function */
static int SDL_MintAudio_max_buf; /* Number of buffers to use */
static int SDL_MintAudio_numbuf; /* Buffer to play */
+static int SDL_MintAudio_num_idle; /* Consecutive refills with spare time */
static void SDL_MintAudio_Callback(void);
@@ -92,7 +98,8 @@ int SDL_MintAudio_InitBuffers(SDL_AudioSpec *spec)
DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%p\n", MINTAUDIO_audiobuf[1]));
SDL_MintAudio_numbuf = SDL_MintAudio_num_its = SDL_MintAudio_num_upd = 0;
- SDL_MintAudio_max_buf = MAX_DMA_BUF;
+ SDL_MintAudio_num_idle = 0;
+ SDL_MintAudio_max_buf = 1;
/* For filling silence when too many interrupts per update */
SDL_MintAudio_itbuffer = NULL;
@@ -140,16 +147,24 @@ void SDL_AtariMint_UpdateAudio(void)
SDL_MintAudio_itbuflen = 0;
- if (SDL_MintAudio_num_upd < (SDL_MintAudio_num_its<<2)) {
- /* Too many interrupts per update, increase latency */
+ if (SDL_MintAudio_num_its > 1) {
+ /* More than one buffer played since the last refill, i.e. the
+ hardware replayed stale data: increase latency */
if (SDL_MintAudio_max_buf < MAX_DMA_BUF) {
SDL_MintAudio_max_buf <<= 1;
}
- } else if (SDL_MintAudio_num_its < (SDL_MintAudio_num_upd<<2)) {
- /* Too many updates per interrupt, decrease latency */
- if (SDL_MintAudio_max_buf > 1) {
- SDL_MintAudio_max_buf >>= 1;
+ SDL_MintAudio_num_idle = 0;
+ } else if (SDL_MintAudio_num_upd >= MIN_UPD_PER_BUF) {
+ /* Updates come often enough, decrease latency once this has held
+ for several buffers in a row */
+ if (++SDL_MintAudio_num_idle >= MIN_IDLE_BUFS) {
+ if (SDL_MintAudio_max_buf > 1) {
+ SDL_MintAudio_max_buf >>= 1;
+ }
+ SDL_MintAudio_num_idle = 0;
}
+ } else {
+ SDL_MintAudio_num_idle = 0;
}
MINTAUDIO_audiosize = this->spec.size * SDL_MintAudio_max_buf;