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();
if (avail < nframes * 2)
{
printf("Underrun\n");
auto zeroed_samples = nframes * 2 - avail;
memset(output_buffer, 0, 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)
{
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",
@ -125,7 +124,7 @@ bool S9xCubebSoundDriver::open_device(int playback_rate, int buffer_size)
return false;
}
buffer.resize(2 * buffer_size * playback_rate / 1000);
buffer.resize(suggested_latency * 4);
return true;
}

View File

@ -74,7 +74,6 @@ bool S9xPortAudioSoundDriver::tryHostAPI(int index)
printf("Host API #%d has no info\n", index);
return false;
}
printf("Attempting API: %s\n", hostapi_info->name);
auto device_info = Pa_GetDeviceInfo(hostapi_info->defaultOutputDevice);
if (!device_info)
@ -104,8 +103,12 @@ bool S9xPortAudioSoundDriver::tryHostAPI(int index)
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);
output_buffer_size = frames;

View File

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

View File

@ -16,7 +16,7 @@ class S9xPulseSoundDriver : public S9xSoundDriver
S9xPulseSoundDriver();
void init() 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;
void start() 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.channels = 2;
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) {
((S9xSDLSoundDriver *)userdata)->mix((unsigned char *)stream, len);
};
@ -83,8 +83,10 @@ bool S9xSDLSoundDriver::open_device(int playback_rate, int buffer_size)
}
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;
}

View File

@ -80,13 +80,19 @@ find_package(Qt6 REQUIRED COMPONENTS Widgets Gui)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL REQUIRED sdl2)
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})
list(APPEND INCLUDES ${SDL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${PORTAUDIO_INCLUDE_DIRS} ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
list(APPEND FLAGS ${SDL_COMPILE_FLAGS} ${ZLIB_COMPILE_FLAGS} ${PORTAUDIO_COMPILE_FLAGS})
pkg_check_modules(PULSEAUDIO REQUIRED libpulse)
if(PULSEAUDIO_FOUND)
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/EmuApplication.cpp
src/EmuMainWindow.cpp
@ -112,8 +118,6 @@ set(QT_GUI_SOURCES
../external/glad/src/gl.c
../common/audio/s9x_sound_driver_sdl.cpp
../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.hpp
../filter/2xsai.cpp
@ -137,7 +141,7 @@ if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
list(APPEND LIBS ${WAYLAND_LIBRARIES} ${X11_LIBRARIES})
list(APPEND FLAGS ${WAYLAND_CFLAGS})
set(PLATFORM_SOURCES
list(APPEND PLATFORM_SOURCES
../common/video/glx_context.cpp
../common/video/wayland_egl_context.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/egl.c)
else()
set(PLATFORM_SOURCES
list(APPEND PLATFORM_SOURCES
../common/video/wgl_context.cpp
../external/glad/src/wgl.c)
list(APPEND LIBS opengl32)

View File

@ -1,12 +1,17 @@
#include "EmuApplication.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 <qlabel.h>
#ifdef USE_PULSEAUDIO
#include "common/audio/s9x_sound_driver_pulse.hpp"
#endif
#include <QTimer>
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
#undef SOUND_BUFFER_WINDOW
EmuApplication::EmuApplication()
{
core = Snes9xController::get();
@ -22,11 +27,14 @@ void EmuApplication::restartAudio()
sound_driver.reset();
core->sound_output_function = nullptr;
if (config->sound_driver == "portaudio")
sound_driver = std::make_unique<S9xPortAudioSoundDriver>();
else if (config->sound_driver == "cubeb")
#ifdef USE_PULSEAUDIO
if (config->sound_driver == "pulseaudio")
sound_driver = std::make_unique<S9xPulseSoundDriver>();
#endif
if (config->sound_driver == "cubeb")
sound_driver = std::make_unique<S9xCubebSoundDriver>();
else
if (!sound_driver)
{
config->sound_driver = "sdl";
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)
{
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())
{
int iterations = 0;
@ -66,34 +105,13 @@ void EmuApplication::writeSamples(int16_t *data, int samples)
if (!sound_driver->write_samples(data, samples))
{
printf("Overrun\n");
core->clearSoundBuffer();
}
char sym = '*';
#ifdef SOUND_BUFFER_WINDOW
int percent = (buffer_level.second - buffer_level.first) * 100 / buffer_level.second;
printf("\033[0;0H>");
if (percent < 50)
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");
trackBufferLevel(percent, window.get());
#endif
}
void EmuApplication::startGame()

View File

@ -89,14 +89,16 @@ void SoundPanel::showEvent(QShowEvent *event)
auto &config = app->config;
comboBox_driver->clear();
comboBox_driver->addItem("SDL");
comboBox_driver->addItem("PortAudio");
comboBox_driver->addItem("Cubeb");
driver_list.clear();
driver_list.push_back("sdl");
driver_list.push_back("portaudio");
comboBox_driver->addItem("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++)
{