Skip to content

Commit 7caeaad

Browse files
committed
Improve audio latency
1 parent a7603da commit 7caeaad

File tree

7 files changed

+62
-22
lines changed

7 files changed

+62
-22
lines changed

platforms/shared/desktop/config.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ void config_read(void)
365365
config_audio.psg_volume = read_float("Audio", "PSGVolume", 1.0f);
366366
config_audio.cdrom_volume = read_float("Audio", "CDROMVolume", 1.0f);
367367
config_audio.adpcm_volume = read_float("Audio", "ADPCMVolume", 1.0f);
368+
config_audio.buffer_count = read_int("Audio", "BufferCount", 3);
368369

369370
config_input.turbo_tap = read_bool("Input", "TurboTap", false);
370371

@@ -632,6 +633,7 @@ void config_write(void)
632633
write_float("Audio", "PSGVolume", config_audio.psg_volume);
633634
write_float("Audio", "CDROMVolume", config_audio.cdrom_volume);
634635
write_float("Audio", "ADPCMVolume", config_audio.adpcm_volume);
636+
write_int("Audio", "BufferCount", config_audio.buffer_count);
635637

636638
write_bool("Input", "TurboTap", config_input.turbo_tap);
637639

platforms/shared/desktop/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ struct config_Audio
108108
float psg_volume = 1.0f;
109109
float cdrom_volume = 1.0f;
110110
float adpcm_volume = 1.0f;
111+
int buffer_count = 3;
111112
};
112113

113114
struct config_Input

platforms/shared/desktop/emu.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ void emu_audio_cdrom_volume(float volume)
337337
void emu_audio_reset(void)
338338
{
339339
sound_queue_stop();
340-
sound_queue_start(GG_AUDIO_SAMPLE_RATE, 2, GG_AUDIO_BUFFER_SIZE, GG_AUDIO_BUFFER_COUNT);
340+
sound_queue_start(GG_AUDIO_SAMPLE_RATE, 2, GG_AUDIO_QUEUE_SIZE, config_audio.buffer_count);
341341
}
342342

343343
bool emu_is_audio_enabled(void)

platforms/shared/desktop/gui_menus.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,26 @@ static void menu_audio(void)
12481248

12491249
ImGui::Separator();
12501250

1251+
if (ImGui::BeginMenu("Buffer Size", config_audio.enable))
1252+
{
1253+
ImGui::PushItemWidth(150.0f);
1254+
if (ImGui::SliderInt("##buffer_count", &config_audio.buffer_count, 2, 5, "Buffers = %d"))
1255+
{
1256+
emu_audio_reset();
1257+
}
1258+
ImGui::PopItemWidth();
1259+
if (ImGui::IsItemHovered())
1260+
{
1261+
float latency_ms = (config_audio.buffer_count * GG_AUDIO_QUEUE_SIZE) / (float)(GG_AUDIO_SAMPLE_RATE * 2) * 1000.0f;
1262+
ImGui::BeginTooltip();
1263+
ImGui::Text("Lower values reduce audio latency.");
1264+
ImGui::Text("Higher values prevent audio underruns.");
1265+
ImGui::Text("Audio latency: %.0f ms", latency_ms);
1266+
ImGui::EndTooltip();
1267+
}
1268+
ImGui::EndMenu();
1269+
}
1270+
12511271
if (ImGui::MenuItem("Sync With Emulator", "", &config_audio.sync))
12521272
{
12531273
config_emulator.ffwd = false;

platforms/shared/desktop/sound_queue.cpp

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ static SDL_AudioStream* sound_queue_stream;
2828
static bool sound_queue_sound_open;
2929
static int sound_queue_max_queued_bytes;
3030
static int sound_queue_buffer_size;
31+
static int sound_queue_bytes_per_second;
3132
static s16* sound_queue_last_written;
3233

3334
static bool is_running_in_wsl(void);
@@ -40,42 +41,42 @@ void sound_queue_init(void)
4041

4142
int audio_drivers_count = SDL_GetNumAudioDrivers();
4243

43-
Debug("SoundQueue: %d audio backends", audio_drivers_count);
44+
Debug("Sound Queue: %d audio drivers", audio_drivers_count);
4445

4546
for (int i = 0; i < audio_drivers_count; i++)
4647
{
47-
Debug("SoundQueue: %s", SDL_GetAudioDriver(i));
48+
Log("Sound Queue: Driver [%s]", SDL_GetAudioDriver(i));
4849
}
4950

5051
std::string platform = SDL_GetPlatform();
5152
if (platform == "Linux")
5253
{
5354
if (is_running_in_wsl())
5455
{
55-
Debug("SoundQueue: Running in WSL");
56+
Debug("Sound Queue: Running in WSL");
5657
SDL_SetHint("SDL_AUDIODRIVER", "pulseaudio");
5758
}
5859
else
5960
{
60-
Debug("SoundQueue: Running in Linux");
61+
Debug("Sound Queue: Running in Linux");
6162
}
6263
}
6364

6465
if (!SDL_InitSubSystem(SDL_INIT_AUDIO))
6566
SDL_ERROR("SDL_InitSubSystem(SDL_INIT_AUDIO)");
6667

67-
Log("SoundQueue: %s driver selected", SDL_GetCurrentAudioDriver());
68+
Log("Sound Queue: [%s] driver selected", SDL_GetCurrentAudioDriver());
6869

6970
int audio_devices_count = 0;
7071
SDL_AudioDeviceID* devices = SDL_GetAudioPlaybackDevices(&audio_devices_count);
7172

72-
Debug("SoundQueue: %d audio devices", audio_devices_count);
73+
Debug("Sound Queue: %d audio devices", audio_devices_count);
7374

7475
if (devices)
7576
{
7677
for (int i = 0; i < audio_devices_count; i++)
7778
{
78-
Debug("SoundQueue: %s", SDL_GetAudioDeviceName(devices[i]));
79+
Log("Sound Queue: Device [%s]", SDL_GetAudioDeviceName(devices[i]));
7980
}
8081
SDL_free(devices);
8182
}
@@ -88,10 +89,11 @@ void sound_queue_destroy(void)
8889

8990
bool sound_queue_start(int sample_rate, int channel_count, int buffer_size, int buffer_count)
9091
{
91-
Log("SoundQueue: Starting with %d Hz, %d channels, %d buffer size, %d buffers ...", sample_rate, channel_count, buffer_size, buffer_count);
92+
Debug("Sound Queue: Starting with %d Hz, %d channels, %d buffer size, %d buffers ...", sample_rate, channel_count, buffer_size, buffer_count);
9293

9394
sound_queue_buffer_size = buffer_size;
9495
sound_queue_max_queued_bytes = buffer_size * buffer_count * (int)sizeof(s16);
96+
sound_queue_bytes_per_second = sample_rate * channel_count * (int)sizeof(s16);
9597

9698
sound_queue_last_written = new s16[buffer_size];
9799
memset(sound_queue_last_written, 0, buffer_size * sizeof(s16));
@@ -101,7 +103,7 @@ bool sound_queue_start(int sample_rate, int channel_count, int buffer_size, int
101103
spec.format = SDL_AUDIO_S16;
102104
spec.channels = channel_count;
103105

104-
Log("SoundQueue: Desired - frequency: %d format: 0x%04X channels: %d", spec.freq, spec.format, spec.channels);
106+
Debug("Sound Queue: Spec - frequency: %d format: 0x%04X channels: %d", spec.freq, spec.format, spec.channels);
105107

106108
sound_queue_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
107109

@@ -111,7 +113,9 @@ bool sound_queue_start(int sample_rate, int channel_count, int buffer_size, int
111113
return false;
112114
}
113115

114-
Log("SoundQueue: Audio stream opened successfully");
116+
SDL_AudioDeviceID selected_device = SDL_GetAudioStreamDevice(sound_queue_stream);
117+
118+
Log("Sound Queue: Started [%s] - frequency: %d format: 0x%04X channels: %d", SDL_GetAudioDeviceName(selected_device), spec.freq, spec.format, spec.channels);
115119

116120
SDL_ResumeAudioStreamDevice(sound_queue_stream);
117121
sound_queue_sound_open = true;
@@ -131,7 +135,7 @@ void sound_queue_stop(void)
131135
InitPointer(sound_queue_stream);
132136
}
133137

134-
Log("SoundQueue: Stopped");
138+
Debug("Sound Queue: Stopped");
135139
}
136140

137141
SafeDeleteArray(sound_queue_last_written);
@@ -160,23 +164,36 @@ void sound_queue_write(s16* samples, int count, bool sync)
160164
return;
161165

162166
int bytes = count * (int)sizeof(s16);
167+
int queued = SDL_GetAudioStreamQueued(sound_queue_stream);
168+
169+
if (count > sound_queue_buffer_size)
170+
{
171+
Log("Sound Queue: Write exceeds queue buffer size (%d > %d)", count, sound_queue_buffer_size);
172+
}
173+
174+
if (queued == 0)
175+
{
176+
Debug("Sound Queue: Underrun detected, queue was empty");
177+
}
163178

164179
if (sync)
165180
{
166-
int queued = SDL_GetAudioStreamQueued(sound_queue_stream);
167-
if (queued >= sound_queue_max_queued_bytes)
181+
int room = sound_queue_max_queued_bytes - queued;
182+
if (room < bytes)
168183
{
169-
Debug("SoundQueue: Sync overrun, queued %d >= max %d, waiting...", queued, sound_queue_max_queued_bytes);
170-
while (SDL_GetAudioStreamQueued(sound_queue_stream) >= sound_queue_max_queued_bytes)
171-
SDL_Delay(1);
184+
Debug("Sound Queue: Sync overrun, queued %d >= max %d, waiting...", queued, sound_queue_max_queued_bytes);
185+
int needed = bytes - room;
186+
int wait_ms = (needed * 1000) / sound_queue_bytes_per_second;
187+
if (wait_ms >= 1)
188+
SDL_Delay(wait_ms);
172189
}
173190
}
174191
else
175192
{
176-
if (SDL_GetAudioStreamQueued(sound_queue_stream) >= sound_queue_max_queued_bytes)
193+
if (queued >= sound_queue_max_queued_bytes)
177194
{
178-
Debug("SoundQueue: Async overrun, clearing stream (queued %d >= max %d)", SDL_GetAudioStreamQueued(sound_queue_stream), sound_queue_max_queued_bytes);
179-
SDL_ClearAudioStream(sound_queue_stream);
195+
Debug("Sound Queue: Async overrun, dropping frame (queued %d >= max %d)", queued, sound_queue_max_queued_bytes);
196+
return;
180197
}
181198
}
182199

platforms/shared/desktop/sound_queue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
EXTERN void sound_queue_init(void);
3434
EXTERN void sound_queue_destroy(void);
35-
EXTERN bool sound_queue_start(int sample_rate, int channel_count, int buffer_size = 2048, int buffer_count = 3);
35+
EXTERN bool sound_queue_start(int sample_rate, int channel_count, int buffer_size = GG_AUDIO_QUEUE_SIZE, int buffer_count = 3);
3636
EXTERN void sound_queue_stop(void);
3737
EXTERN void sound_queue_write(s16* samples, int count, bool sync);
3838
EXTERN int sound_queue_get_sample_count(void);

src/defines.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
#define GG_AUDIO_SAMPLE_RATE 44100
4747
#define GG_AUDIO_BUFFER_SIZE 2048
48-
#define GG_AUDIO_BUFFER_COUNT 3
48+
#define GG_AUDIO_QUEUE_SIZE 1500
4949
#define GG_PSG_CYCLES_PER_SAMPLE 81
5050
#define GG_CDAUDIO_CYCLES_PER_SAMPLE 486
5151

0 commit comments

Comments
 (0)