Sound buffer tweaking.

This commit is contained in:
BearOso 2023-06-29 17:44:13 -05:00
parent bafea657e7
commit 62c4686fc6
8 changed files with 98 additions and 62 deletions

View File

@ -80,7 +80,6 @@ long S9xCubebSoundDriver::data_callback(cubeb_stream *stream, void const *input_
auto avail = buffer.avail(); auto avail = buffer.avail();
if (avail < nframes * 2) if (avail < nframes * 2)
{ {
printf("Underrun\n");
auto zeroed_samples = nframes * 2 - avail; auto zeroed_samples = nframes * 2 - avail;
memset(output_buffer, 0, zeroed_samples); memset(output_buffer, 0, zeroed_samples);
buffer.read((int16_t *)output_buffer + zeroed_samples, nframes * 2 - zeroed_samples); buffer.read((int16_t *)output_buffer + zeroed_samples, nframes * 2 - zeroed_samples);
@ -107,7 +106,7 @@ bool S9xCubebSoundDriver::open_device(int playback_rate, int buffer_size)
if (min_latency > suggested_latency) if (min_latency > suggested_latency)
{ {
suggested_latency = min_latency; suggested_latency = min_latency;
printf("Using minimum latency: %d\n", min_latency); printf("Requires a minimum latency: %d\n", min_latency);
} }
auto retval = cubeb_stream_init(context, &stream, "Snes9x", auto retval = cubeb_stream_init(context, &stream, "Snes9x",
@ -125,7 +124,7 @@ bool S9xCubebSoundDriver::open_device(int playback_rate, int buffer_size)
return false; return false;
} }
buffer.resize(2 * buffer_size * playback_rate / 1000); buffer.resize(suggested_latency * 4);
return true; return true;
} }

View File

@ -74,7 +74,6 @@ bool S9xPortAudioSoundDriver::tryHostAPI(int index)
printf("Host API #%d has no info\n", index); printf("Host API #%d has no info\n", index);
return false; return false;
} }
printf("Attempting API: %s\n", hostapi_info->name);
auto device_info = Pa_GetDeviceInfo(hostapi_info->defaultOutputDevice); auto device_info = Pa_GetDeviceInfo(hostapi_info->defaultOutputDevice);
if (!device_info) if (!device_info)
@ -104,8 +103,12 @@ bool S9xPortAudioSoundDriver::tryHostAPI(int index)
NULL, NULL,
NULL); NULL);
int frames = playback_rate * buffer_size_ms / 1000; int frames = Pa_GetStreamWriteAvailable(audio_stream);
//int frames = Pa_GetStreamWriteAvailable(audio_stream); if (frames < 0)
{
Pa_Sleep(10);
frames = Pa_GetStreamWriteAvailable(audio_stream);
}
printf("PortAudio set buffer size to %d frames.\n", frames); printf("PortAudio set buffer size to %d frames.\n", frames);
output_buffer_size = frames; output_buffer_size = frames;
@ -181,7 +184,7 @@ int S9xPortAudioSoundDriver::space_free()
std::pair<int, int> S9xPortAudioSoundDriver::buffer_level() std::pair<int, int> S9xPortAudioSoundDriver::buffer_level()
{ {
return { Pa_GetStreamWriteAvailable(audio_stream), output_buffer_size }; return { Pa_GetStreamWriteAvailable(audio_stream), output_buffer_size };
} }
bool S9xPortAudioSoundDriver::write_samples(int16_t *data, int samples) bool S9xPortAudioSoundDriver::write_samples(int16_t *data, int samples)

View File

@ -181,16 +181,22 @@ std::pair<int, int> S9xPulseSoundDriver::buffer_level()
return { bytes, buffer_size }; return { bytes, buffer_size };
} }
void S9xPulseSoundDriver::write_samples(int16_t *data, int samples) bool S9xPulseSoundDriver::write_samples(int16_t *data, int samples)
{ {
bool retval = true;
lock(); lock();
size_t bytes = pa_stream_writable_size(stream); size_t bytes = pa_stream_writable_size(stream);
unlock(); unlock();
bytes = MIN(bytes, samples * 2) & ~1; if (samples * 2 > bytes)
return false;
if (samples * 2 < bytes)
bytes = samples * 2;
if (bytes == 0) if (bytes == 0)
return; return false;
lock(); lock();
void *output_buffer; void *output_buffer;
@ -198,16 +204,18 @@ void S9xPulseSoundDriver::write_samples(int16_t *data, int samples)
{ {
pa_stream_flush(stream, nullptr, nullptr); pa_stream_flush(stream, nullptr, nullptr);
unlock(); unlock();
return; return false;
} }
if (bytes <= 0 || !output_buffer) if (bytes <= 0 || !output_buffer)
{ {
unlock(); unlock();
return; return false;
} }
std::memcpy(output_buffer, data, bytes); std::memcpy(output_buffer, data, bytes);
pa_stream_write(stream, output_buffer, bytes, nullptr, 0, PA_SEEK_RELATIVE); pa_stream_write(stream, output_buffer, bytes, nullptr, 0, PA_SEEK_RELATIVE);
unlock(); unlock();
return retval;
} }

View File

@ -16,7 +16,7 @@ class S9xPulseSoundDriver : public S9xSoundDriver
S9xPulseSoundDriver(); S9xPulseSoundDriver();
void init() override; void init() override;
void deinit() override; void deinit() override;
void write_samples(int16_t *data, int samples) override; bool write_samples(int16_t *data, int samples) override;
bool open_device(int playback_rate, int buffer_size) override; bool open_device(int playback_rate, int buffer_size) override;
void start() override; void start() override;
void stop() override; void stop() override;

View File

@ -64,7 +64,7 @@ bool S9xSDLSoundDriver::open_device(int playback_rate, int buffer_size)
audiospec.freq = playback_rate; audiospec.freq = playback_rate;
audiospec.channels = 2; audiospec.channels = 2;
audiospec.format = AUDIO_S16SYS; audiospec.format = AUDIO_S16SYS;
audiospec.samples = audiospec.freq * 4 / 1000; // 4ms per sampling audiospec.samples = audiospec.freq * buffer_size / 8 / 1000; // 1/8th buffer per callback
audiospec.callback = [](void *userdata, uint8_t *stream, int len) { audiospec.callback = [](void *userdata, uint8_t *stream, int len) {
((S9xSDLSoundDriver *)userdata)->mix((unsigned char *)stream, len); ((S9xSDLSoundDriver *)userdata)->mix((unsigned char *)stream, len);
}; };
@ -83,8 +83,10 @@ bool S9xSDLSoundDriver::open_device(int playback_rate, int buffer_size)
} }
printf("OK\n"); printf("OK\n");
if (buffer_size < 32)
buffer_size = 32;
buffer.resize(buffer_size * audiospec.freq / 1000); buffer.resize(buffer_size * 4 * audiospec.freq / 1000);
return true; return true;
} }

View File

@ -80,13 +80,19 @@ find_package(Qt6 REQUIRED COMPONENTS Widgets Gui)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL REQUIRED sdl2) pkg_check_modules(SDL REQUIRED sdl2)
pkg_check_modules(ZLIB REQUIRED zlib) pkg_check_modules(ZLIB REQUIRED zlib)
pkg_check_modules(PORTAUDIO REQUIRED portaudio-2.0) list(APPEND LIBS Qt6::Widgets Qt6::Gui ${SDL_LIBRARIES} ${ZLIB_LIBRARIES})
list(APPEND INCLUDES ${SDL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}${Qt6Gui_PRIVATE_INCLUDE_DIRS})
list(APPEND FLAGS ${SDL_COMPILE_FLAGS} ${ZLIB_COMPILE_FLAGS})
list(APPEND LIBS Qt6::Widgets Qt6::Gui ${SDL_LIBRARIES} ${ZLIB_LIBRARIES} ${PORTAUDIO_LIBRARIES}) pkg_check_modules(PULSEAUDIO REQUIRED libpulse)
list(APPEND INCLUDES ${SDL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${PORTAUDIO_INCLUDE_DIRS} ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) if(PULSEAUDIO_FOUND)
list(APPEND FLAGS ${SDL_COMPILE_FLAGS} ${ZLIB_COMPILE_FLAGS} ${PORTAUDIO_COMPILE_FLAGS}) list(APPEND LIBS ${PULSEAUDIO_LIBRARIES})
list(APPEND INCLUDES ${PULSEAUDIO_INCLUDE_DIRS})
list(APPEND DEFINES "USE_PULSEAUDIO")
list(APPEND PLATFORM_SOURCES ../common/audio/s9x_sound_driver_pulse.cpp)
endif()
set(QT_GUI_SOURCES list(APPEND QT_GUI_SOURCES
src/main.cpp src/main.cpp
src/EmuApplication.cpp src/EmuApplication.cpp
src/EmuMainWindow.cpp src/EmuMainWindow.cpp
@ -112,8 +118,6 @@ set(QT_GUI_SOURCES
../external/glad/src/gl.c ../external/glad/src/gl.c
../common/audio/s9x_sound_driver_sdl.cpp ../common/audio/s9x_sound_driver_sdl.cpp
../common/audio/s9x_sound_driver_sdl.hpp ../common/audio/s9x_sound_driver_sdl.hpp
../common/audio/s9x_sound_driver_portaudio.cpp
../common/audio/s9x_sound_driver_portaudio.hpp
../common/audio/s9x_sound_driver_cubeb.cpp ../common/audio/s9x_sound_driver_cubeb.cpp
../common/audio/s9x_sound_driver_cubeb.hpp ../common/audio/s9x_sound_driver_cubeb.hpp
../filter/2xsai.cpp ../filter/2xsai.cpp
@ -137,7 +141,7 @@ if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
list(APPEND LIBS ${WAYLAND_LIBRARIES} ${X11_LIBRARIES}) list(APPEND LIBS ${WAYLAND_LIBRARIES} ${X11_LIBRARIES})
list(APPEND FLAGS ${WAYLAND_CFLAGS}) list(APPEND FLAGS ${WAYLAND_CFLAGS})
set(PLATFORM_SOURCES list(APPEND PLATFORM_SOURCES
../common/video/glx_context.cpp ../common/video/glx_context.cpp
../common/video/wayland_egl_context.cpp ../common/video/wayland_egl_context.cpp
../common/video/wayland_surface.cpp ../common/video/wayland_surface.cpp
@ -147,7 +151,7 @@ if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
../external/glad/src/glx.c ../external/glad/src/glx.c
../external/glad/src/egl.c) ../external/glad/src/egl.c)
else() else()
set(PLATFORM_SOURCES list(APPEND PLATFORM_SOURCES
../common/video/wgl_context.cpp ../common/video/wgl_context.cpp
../external/glad/src/wgl.c) ../external/glad/src/wgl.c)
list(APPEND LIBS opengl32) list(APPEND LIBS opengl32)

View File

@ -1,12 +1,17 @@
#include "EmuApplication.hpp" #include "EmuApplication.hpp"
#include "common/audio/s9x_sound_driver_sdl.hpp" #include "common/audio/s9x_sound_driver_sdl.hpp"
#include "common/audio/s9x_sound_driver_portaudio.hpp"
#include "common/audio/s9x_sound_driver_cubeb.hpp" #include "common/audio/s9x_sound_driver_cubeb.hpp"
#include <qlabel.h>
#ifdef USE_PULSEAUDIO
#include "common/audio/s9x_sound_driver_pulse.hpp"
#endif
#include <QTimer> #include <QTimer>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
#undef SOUND_BUFFER_WINDOW
EmuApplication::EmuApplication() EmuApplication::EmuApplication()
{ {
core = Snes9xController::get(); core = Snes9xController::get();
@ -22,11 +27,14 @@ void EmuApplication::restartAudio()
sound_driver.reset(); sound_driver.reset();
core->sound_output_function = nullptr; core->sound_output_function = nullptr;
if (config->sound_driver == "portaudio") #ifdef USE_PULSEAUDIO
sound_driver = std::make_unique<S9xPortAudioSoundDriver>(); if (config->sound_driver == "pulseaudio")
else if (config->sound_driver == "cubeb") sound_driver = std::make_unique<S9xPulseSoundDriver>();
#endif
if (config->sound_driver == "cubeb")
sound_driver = std::make_unique<S9xCubebSoundDriver>(); sound_driver = std::make_unique<S9xCubebSoundDriver>();
else
if (!sound_driver)
{ {
config->sound_driver = "sdl"; config->sound_driver = "sdl";
sound_driver = std::make_unique<S9xSDLSoundDriver>(); sound_driver = std::make_unique<S9xSDLSoundDriver>();
@ -47,11 +55,42 @@ void EmuApplication::restartAudio()
}; };
} }
#ifdef SOUND_BUFFER_WINDOW
#include <QProgressDialog>
static void trackBufferLevel(int percent, QWidget *parent)
{
static uint64_t total = 0;
static uint64_t ticks = 0;
static std::chrono::steady_clock::time_point then;
static QProgressDialog *dialog = nullptr;
if (!dialog)
{
dialog = new QProgressDialog(parent);
dialog->setRange(0, 100);
}
ticks++;
total += percent;
dialog->setValue(percent);
auto now = std::chrono::steady_clock::now();
if (ticks > 0 && now - then >= std::chrono::seconds(1))
{
dialog->setLabelText(QString("%1").arg(total / ticks));
then = now;
total = 0;
ticks = 0;
}
if (!dialog->isVisible())
dialog->show();
}
#endif
void EmuApplication::writeSamples(int16_t *data, int samples) void EmuApplication::writeSamples(int16_t *data, int samples)
{ {
static uint64_t total;
static uint64_t ticks;
static std::chrono::steady_clock::time_point then;
if (config->speed_sync_method == EmuConfig::eSoundSync && !core->isAbnormalSpeed()) if (config->speed_sync_method == EmuConfig::eSoundSync && !core->isAbnormalSpeed())
{ {
int iterations = 0; int iterations = 0;
@ -66,34 +105,13 @@ void EmuApplication::writeSamples(int16_t *data, int samples)
if (!sound_driver->write_samples(data, samples)) if (!sound_driver->write_samples(data, samples))
{ {
printf("Overrun\n");
core->clearSoundBuffer(); core->clearSoundBuffer();
} }
char sym = '*'; #ifdef SOUND_BUFFER_WINDOW
int percent = (buffer_level.second - buffer_level.first) * 100 / buffer_level.second; int percent = (buffer_level.second - buffer_level.first) * 100 / buffer_level.second;
printf("\033[0;0H>"); trackBufferLevel(percent, window.get());
if (percent < 50) #endif
sym = '_';
for (int i = 0; i < percent; i+=2)
putchar(sym);
for (int i = percent; i <= 100; i+=2)
putchar('-');
total += percent;
ticks++;
auto now = std::chrono::steady_clock::now();
if (now - then >= std::chrono::seconds(1))
{
then = now;
printf(" %lu %%", total / ticks);
total = 0;
ticks = 0;
}
printf("\n");
printf(" 10 20 30 40 50 60 70 80 90 100");
} }
void EmuApplication::startGame() void EmuApplication::startGame()

View File

@ -89,14 +89,16 @@ void SoundPanel::showEvent(QShowEvent *event)
auto &config = app->config; auto &config = app->config;
comboBox_driver->clear(); comboBox_driver->clear();
comboBox_driver->addItem("SDL");
comboBox_driver->addItem("PortAudio");
comboBox_driver->addItem("Cubeb");
driver_list.clear(); driver_list.clear();
driver_list.push_back("sdl");
driver_list.push_back("portaudio"); comboBox_driver->addItem("Cubeb");
driver_list.push_back("cubeb"); driver_list.push_back("cubeb");
comboBox_driver->addItem("SDL");
driver_list.push_back("sdl");
#ifdef USE_PULSEAUDIO
comboBox_driver->addItem("PulseAudio");
driver_list.push_back("pulseaudio");
#endif
for (int i = 0; i < driver_list.size(); i++) for (int i = 0; i < driver_list.size(); i++)
{ {