mirror of https://github.com/snes9xgit/snes9x.git
Sound buffer tweaking.
This commit is contained in:
parent
bafea657e7
commit
62c4686fc6
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -181,7 +184,7 @@ int S9xPortAudioSoundDriver::space_free()
|
|||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue