From a4b2b2d9efa3c8c16940586cf731d841af0b33af Mon Sep 17 00:00:00 2001
From: Miro Kropacek <[EMAIL REDACTED]>
Date: Thu, 1 Oct 2026 22:22:21 +1000
Subject: [PATCH] atari:audio:xbios: FireTOS lacks end-of-frame interrupt
Use polling instead. I keep forgetting about this, again and again.
---
src/audio/mint/SDL_mintaudio.c | 31 ++++++++++++++++++++++++++++
src/audio/mint/SDL_mintaudio_xbios.c | 23 +++++++++++----------
2 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/src/audio/mint/SDL_mintaudio.c b/src/audio/mint/SDL_mintaudio.c
index a05109073..b95e98359 100644
--- a/src/audio/mint/SDL_mintaudio.c
+++ b/src/audio/mint/SDL_mintaudio.c
@@ -42,6 +42,7 @@
/* The audio device */
#define MAX_DMA_BUF 8
+#define POLL_DMA_BUF 2
/* Minimum number of updates per buffer, and number of consecutive buffers
meeting it, before the latency is decreased */
@@ -76,7 +77,12 @@ int SDL_MintAudio_InitBuffers(SDL_AudioSpec *spec)
SDL_AudioDevice *this = SDL_MintAudio_device;
SDL_CalculateAudioSpec(spec);
+#if defined(__mcoldfire__)
+ /* Fixed size: both halves of the ring must stay contiguous */
+ MINTAUDIO_audiosize = spec->size * POLL_DMA_BUF;
+#else
MINTAUDIO_audiosize = spec->size * MAX_DMA_BUF;
+#endif
/* Allocate audio buffer memory for application in FastRAM */
MINTAUDIO_fastrambuf = Atari_SysMalloc(MINTAUDIO_audiosize, MX_TTRAM);
@@ -99,7 +105,11 @@ int SDL_MintAudio_InitBuffers(SDL_AudioSpec *spec)
SDL_MintAudio_numbuf = SDL_MintAudio_num_its = SDL_MintAudio_num_upd = 0;
SDL_MintAudio_num_idle = 0;
+#if defined(__mcoldfire__)
+ SDL_MintAudio_max_buf = POLL_DMA_BUF;
+#else
SDL_MintAudio_max_buf = 1;
+#endif
/* For filling silence when too many interrupts per update */
SDL_MintAudio_itbuffer = NULL;
@@ -138,6 +148,26 @@ void SDL_AtariMint_UpdateAudio(void)
return;
}
+#if defined(__mcoldfire__)
+ {
+ SndBufPtr pointers;
+ int playing;
+
+ if (Buffptr(&pointers) != 0) {
+ return;
+ }
+
+ /* Here SDL_MintAudio_numbuf is the half being replayed */
+ playing = ((Uint8 *)pointers.play >= MINTAUDIO_audiobuf[1]);
+ if (playing == SDL_MintAudio_numbuf) {
+ return;
+ }
+
+ /* Refill the half the replay has just left */
+ SDL_MintAudio_Callback();
+ SDL_MintAudio_numbuf = playing;
+ }
+#else
++SDL_MintAudio_num_upd;
/* No interrupt triggered? still playing current buffer */
@@ -181,6 +211,7 @@ void SDL_AtariMint_UpdateAudio(void)
SDL_MintAudio_itbuffer = MINTAUDIO_audiobuf[SDL_MintAudio_numbuf];
SDL_MintAudio_itbuflen = MINTAUDIO_audiosize >> 2;
+#endif
}
/* The callback function, called by each driver whenever needed */
diff --git a/src/audio/mint/SDL_mintaudio_xbios.c b/src/audio/mint/SDL_mintaudio_xbios.c
index 999ada088..7709e60c3 100644
--- a/src/audio/mint/SDL_mintaudio_xbios.c
+++ b/src/audio/mint/SDL_mintaudio_xbios.c
@@ -82,10 +82,10 @@ static void Mint_GsxbNullInterrupt(void);
/* uSound state, shared between Mint_OpenAudio() and Mint_CloseAudio() */
static USoundContext usound_context;
-/* Do we use GSXB's own end of frame callback instead of Timer A ? */
-#if defined(__mcoldfire__)
-#define use_gsxb 0 /* no ColdFire machine implements GSXB */
-#else
+/* Do we use GSXB's own end of frame callback instead of Timer A ?
+ ColdFire machines have neither: FireTOS raises no end of frame
+ interrupt, so the replay position is polled instead. */
+#if !defined(__mcoldfire__)
static int use_gsxb;
#endif
@@ -216,11 +216,10 @@ static void Mint_CloseAudio(_THIS)
#if !defined(__mcoldfire__)
if (use_gsxb) {
NSetinterrupt(SI_GSXB, SI_NONE, Mint_GsxbNullInterrupt);
- }
-#endif
- if (!use_gsxb) {
+ } else {
Jdisint(MFP_DMASOUND);
}
+#endif
/* Restore and unlock the sound system */
USoundDeinitXbios(&usound_context);
@@ -281,10 +280,13 @@ static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
/* Set buffer */
MINTAUDIO_swapbuf = Mint_SwapBuffers;
+#if defined(__mcoldfire__)
+ /* Both halves of the ring at once, replayed in a loop */
+ Mint_SwapBuffers(MINTAUDIO_audiobuf[0], 2 * MINTAUDIO_audiosize);
+#else
Mint_SwapBuffers(MINTAUDIO_audiobuf[0], MINTAUDIO_audiosize);
/* Install interrupt */
-#if !defined(__mcoldfire__)
use_gsxb = Mint_GsxbAvailable();
if (use_gsxb) {
if (NSetinterrupt(SI_GSXB, SI_PLAY, SDL_MintAudio_GsxbInterrupt)<0) {
@@ -294,9 +296,7 @@ static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
SDL_MintAudio_device = NULL;
return(-1);
}
- }
-#endif
- if (!use_gsxb) {
+ } else {
Jdisint(MFP_DMASOUND);
Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);
Jenabint(MFP_DMASOUND);
@@ -305,6 +305,7 @@ static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
}
}
+#endif
/* Go */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);