diff -urN visualboyadvance-m-2.1.11-orig/src/core/base/sound_driver.h visualboyadvance-m-2.1.11/src/core/base/sound_driver.h
--- visualboyadvance-m-2.1.11-orig/src/core/base/sound_driver.h	2024-09-15 14:48:38 +0900
+++ visualboyadvance-m-2.1.11/src/core/base/sound_driver.h	2025-03-15 21:54:24 +0900
@@ -28,7 +28,7 @@
 
     // Initialize the sound driver. `sampleRate` in Hertz.
     // Returns true if the driver was successfully initialized.
-    virtual bool init(long sampleRate) = 0;
+    virtual bool init(long sampleRate, float bufferMax, float bufferMin) = 0;
 
     // Pause the sound driver.
     virtual void pause() = 0;
diff -urN visualboyadvance-m-2.1.11-orig/src/core/gba/gbaSound.cpp visualboyadvance-m-2.1.11/src/core/gba/gbaSound.cpp
--- visualboyadvance-m-2.1.11-orig/src/core/gba/gbaSound.cpp	2024-09-15 14:48:38 +0900
+++ visualboyadvance-m-2.1.11/src/core/gba/gbaSound.cpp	2025-03-15 21:52:38 +0900
@@ -42,6 +42,8 @@
 
 static uint16_t soundFinalWave[1600];
 long soundSampleRate = 44100;
+float soundBufferMax = 0.3;
+float soundBufferMin = 0.3;
 bool g_gbaSoundInterpolation = true;
 bool soundPaused = true;
 float soundFiltering = 0.5f;
@@ -504,6 +506,12 @@
     return soundVolume;
 }
 
+void soundSetBufferSize(float bufferMax, float bufferMin)
+{
+    soundBufferMax = bufferMax;
+    soundBufferMin = bufferMin;
+}
+
 void soundSetEnable(int channels)
 {
     soundEnableFlag = channels;
@@ -537,7 +545,7 @@
     if (!soundDriver)
         return false;
 
-    if (!soundDriver->init(soundSampleRate))
+    if (!soundDriver->init(soundSampleRate, soundBufferMax, soundBufferMin))
         return false;
 
     if (!stereo_buffer) {
diff -urN visualboyadvance-m-2.1.11-orig/src/core/gba/gbaSound.h visualboyadvance-m-2.1.11/src/core/gba/gbaSound.h
--- visualboyadvance-m-2.1.11-orig/src/core/gba/gbaSound.h	2024-09-15 14:48:38 +0900
+++ visualboyadvance-m-2.1.11/src/core/gba/gbaSound.h	2025-03-15 21:52:45 +0900
@@ -22,6 +22,11 @@
 void soundSetVolume(float);
 float soundGetVolume();
 
+// Manages sound output buffer size
+// Up to bufferMax seconds will be buffered; buffered data will be sent
+// to the output device until less than bufferMin seconds remain
+void soundSetBufferSize(float bufferMax, float bufferMin);
+
 // Manages muting bitmask. The bits control the following channels:
 // 0x001 Pulse 1
 // 0x002 Pulse 2
diff -urN visualboyadvance-m-2.1.11-orig/src/sdl/ConfigManager.cpp visualboyadvance-m-2.1.11/src/sdl/ConfigManager.cpp
--- visualboyadvance-m-2.1.11-orig/src/sdl/ConfigManager.cpp	2024-09-15 14:48:38 +0900
+++ visualboyadvance-m-2.1.11/src/sdl/ConfigManager.cpp	2025-03-15 21:52:45 +0900
@@ -383,6 +383,10 @@
 		gb_effects_config.enabled = true;
 	}
 
+	int soundBufferMax = ReadPref("soundBufferMax", 300);
+	int soundBufferMin = ReadPref("soundBufferMin", 300);
+	soundSetBufferSize(soundBufferMax / 1000.0f, soundBufferMin / 1000.0f);
+
 	if (optFlashSize == 0)
 		flashSetSize(0x10000);
 	else
diff -urN visualboyadvance-m-2.1.11-orig/src/sdl/audio_sdl.cpp visualboyadvance-m-2.1.11/src/sdl/audio_sdl.cpp
--- visualboyadvance-m-2.1.11-orig/src/sdl/audio_sdl.cpp	2024-09-15 14:48:38 +0900
+++ visualboyadvance-m-2.1.11/src/sdl/audio_sdl.cpp	2025-03-15 21:52:05 +0900
@@ -27,9 +27,6 @@
 
 extern int emulating;
 
-// Hold up to 100 ms of data in the ring buffer
-const double SoundSDL::buftime = 0.100;
-
 SoundSDL::SoundSDL():
     samples_buf(0),
     sound_device(0),
@@ -113,10 +110,16 @@
     samples_buf.write(finalWave, samples * 2);
 
     SDL_UnlockMutex(mutex);
+
+    if (samples_buf.used() >= writeThreshold) {
+	SDL_SemPost(data_available);
+	if (should_wait())
+	    SDL_SemWait(data_read);
+    }
 }
 
 
-bool SoundSDL::init(long sampleRate) {
+bool SoundSDL::init(long sampleRate, float bufferMax, float bufferMin) {
     if (initialized) deinit();
 
     SDL_AudioSpec audio;
@@ -140,7 +143,11 @@
         return false;
     }
 
-    samples_buf.reset(static_cast<size_t>(std::ceil(buftime * sampleRate * 2)));
+    this->bufferMax = bufferMax;
+    this->bufferMin = bufferMin;
+    bufferSize = static_cast<int>(std::ceil(bufferMax * sampleRate * 2));
+    writeThreshold = static_cast<int>(std::ceil(bufferMin * sampleRate * 2));
+    samples_buf.reset(bufferSize);
 
     mutex          = SDL_CreateMutex();
     data_available = SDL_CreateSemaphore(0);
@@ -191,7 +198,7 @@
 void SoundSDL::resume() {}
 
 void SoundSDL::reset() {
-    init(soundGetSampleRate());
+    init(soundGetSampleRate(), bufferMin, bufferMax);
 }
 
 void SoundSDL::setThrottle(unsigned short throttle_) {
diff -urN visualboyadvance-m-2.1.11-orig/src/sdl/audio_sdl.h visualboyadvance-m-2.1.11/src/sdl/audio_sdl.h
--- visualboyadvance-m-2.1.11-orig/src/sdl/audio_sdl.h	2024-09-15 14:48:38 +0900
+++ visualboyadvance-m-2.1.11/src/sdl/audio_sdl.h	2025-03-15 21:53:09 +0900
@@ -36,7 +36,7 @@
         void deinit();
 
         // SoundDriver implementation.
-        bool init(long sampleRate) override;
+        bool init(long sampleRate, float bufferMax, float bufferMin) override;
         void pause() override;
         void reset() override;
         void resume() override;
@@ -53,6 +53,10 @@
         SDL_AudioSpec audio_spec;
 
         unsigned short current_rate;
+	float bufferMax;
+	float bufferMin;
+	int bufferSize;
+	int writeThreshold;
 
         bool initialized = false;
 
