all repos — mgba @ 9c5852e89ea26959c7a1872c7cee8d02e11d2317

mGBA Game Boy Advance Emulator

SDL, Qt: Configurable audio sample rate
Jeffrey Pfau jeffrey@endrift.com
Sun, 09 Aug 2015 21:36:43 -0700
commit

9c5852e89ea26959c7a1872c7cee8d02e11d2317

parent

805e0b17eb3e7cb1cb6e01370811d7c9dd7f0377

M CHANGESCHANGES

@@ -31,6 +31,7 @@ - Libretro now supports BIOS, rumble and solar sensor

- Implement BIOS call Stop, for sleep mode - Automatically load patches, if found - Improved video synchronization + - Configurable audio output sample rate Bugfixes: - ARM7: Fix SWI and IRQ timings - GBA Audio: Force audio FIFOs to 32-bit
M src/gba/supervisor/config.csrc/gba/supervisor/config.c

@@ -247,6 +247,7 @@ unsigned audioBuffers;

if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) { opts->audioBuffers = audioBuffers; } + _lookupUIntValue(config, "sampleRate", &opts->sampleRate); int fakeBool; if (_lookupIntValue(config, "useBios", &fakeBool)) {

@@ -305,6 +306,7 @@ ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity);

ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferInterval", opts->rewindBufferInterval); ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget); ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers); + ConfigurationSetUIntValue(&config->defaultsTable, 0, "sampleRate", opts->sampleRate); ConfigurationSetIntValue(&config->defaultsTable, 0, "audioSync", opts->audioSync); ConfigurationSetIntValue(&config->defaultsTable, 0, "videoSync", opts->videoSync); ConfigurationSetIntValue(&config->defaultsTable, 0, "fullscreen", opts->fullscreen);
M src/gba/supervisor/config.hsrc/gba/supervisor/config.h

@@ -29,6 +29,7 @@ int rewindBufferCapacity;

int rewindBufferInterval; float fpsTarget; size_t audioBuffers; + unsigned sampleRate; int fullscreen; int width;
M src/platform/qt/AudioProcessor.hsrc/platform/qt/AudioProcessor.h

@@ -31,6 +31,7 @@ AudioProcessor(QObject* parent = nullptr);

virtual void setInput(GBAThread* input); int getBufferSamples() const { return m_samples; } + virtual unsigned sampleRate() const = 0; public slots: virtual void start() = 0;

@@ -39,7 +40,7 @@

virtual void setBufferSamples(int samples) = 0; virtual void inputParametersChanged() = 0; - virtual unsigned sampleRate() const = 0; + virtual void requestSampleRate(unsigned) = 0; protected: GBAThread* input() { return m_context; }
M src/platform/qt/AudioProcessorQt.cppsrc/platform/qt/AudioProcessorQt.cpp

@@ -20,6 +20,7 @@ AudioProcessorQt::AudioProcessorQt(QObject* parent)

: AudioProcessor(parent) , m_audioOutput(nullptr) , m_device(nullptr) + , m_sampleRate(44100) { }

@@ -45,7 +46,7 @@ }

if (!m_audioOutput) { QAudioFormat format; - format.setSampleRate(44100); + format.setSampleRate(m_sampleRate); format.setChannelCount(2); format.setSampleSize(16); format.setCodec("audio/pcm");

@@ -81,6 +82,15 @@

void AudioProcessorQt::inputParametersChanged() { if (m_device) { m_device->setFormat(m_audioOutput->format()); + } +} + +void AudioProcessorQt::requestSampleRate(unsigned rate) { + m_sampleRate = rate; + if (m_device) { + QAudioFormat format(m_audioOutput->format()); + format.setSampleRate(rate); + m_device->setFormat(format); } }
M src/platform/qt/AudioProcessorQt.hsrc/platform/qt/AudioProcessorQt.h

@@ -20,6 +20,7 @@ public:

AudioProcessorQt(QObject* parent = nullptr); virtual void setInput(GBAThread* input); + virtual unsigned sampleRate() const override; public slots: virtual void start();

@@ -28,11 +29,12 @@

virtual void setBufferSamples(int samples); virtual void inputParametersChanged(); - virtual unsigned sampleRate() const override; + virtual void requestSampleRate(unsigned) override; private: QAudioOutput* m_audioOutput; AudioDevice* m_device; + unsigned m_sampleRate; }; }
M src/platform/qt/AudioProcessorSDL.cppsrc/platform/qt/AudioProcessorSDL.cpp

@@ -15,7 +15,7 @@ using namespace QGBA;

AudioProcessorSDL::AudioProcessorSDL(QObject* parent) : AudioProcessor(parent) - , m_audio() + , m_audio{ 2048, 44100 } { }

@@ -55,6 +55,18 @@

void AudioProcessorSDL::inputParametersChanged() { } +void AudioProcessorSDL::requestSampleRate(unsigned rate) { + m_audio.sampleRate = rate; + if (m_audio.thread) { + GBASDLDeinitAudio(&m_audio); + GBASDLInitAudio(&m_audio, input()); + } +} + unsigned AudioProcessorSDL::sampleRate() const { - return m_audio.obtainedSpec.freq; + if (m_audio.thread) { + return m_audio.obtainedSpec.freq; + } else { + return 0; + } }
M src/platform/qt/AudioProcessorSDL.hsrc/platform/qt/AudioProcessorSDL.h

@@ -22,6 +22,8 @@ public:

AudioProcessorSDL(QObject* parent = nullptr); ~AudioProcessorSDL(); + virtual unsigned sampleRate() const override; + public slots: virtual void start(); virtual void pause();

@@ -29,7 +31,7 @@

virtual void setBufferSamples(int samples); virtual void inputParametersChanged(); - virtual unsigned sampleRate() const override; + virtual void requestSampleRate(unsigned) override; private: GBASDLAudio m_audio;
M src/platform/qt/GBAApp.cppsrc/platform/qt/GBAApp.cpp

@@ -53,6 +53,7 @@ ::exit(0);

return; } + AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt())); Window* w = new Window(&m_configController); connect(w, &Window::destroyed, [this]() { m_windows[0] = nullptr;

@@ -66,9 +67,6 @@ w->loadConfig();

} freeArguments(&args); w->show(); - - AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt())); - w->controller()->reloadAudioDriver(); w->controller()->setMultiplayerController(&m_multiplayer); }
M src/platform/qt/GameController.cppsrc/platform/qt/GameController.cpp

@@ -87,7 +87,9 @@ setLuminanceLevel(0);

m_threadContext.startCallback = [](GBAThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - controller->m_audioProcessor->setInput(context); + if (controller->m_audioProcessor) { + controller->m_audioProcessor->setInput(context); + } context->gba->luminanceSource = &controller->m_lux; GBARTCGenericSourceInit(&controller->m_rtc, context->gba); context->gba->rtcSource = &controller->m_rtc.d;

@@ -588,10 +590,21 @@ updateKeys();

} void GameController::setAudioBufferSamples(int samples) { - threadInterrupt(); - redoSamples(samples); - threadContinue(); - QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples)); + if (m_audioProcessor) { + threadInterrupt(); + redoSamples(samples); + threadContinue(); + QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples)); + } +} + +void GameController::setAudioSampleRate(unsigned rate) { + if (m_audioProcessor) { + threadInterrupt(); + redoSamples(m_audioProcessor->getBufferSamples()); + threadContinue(); + QMetaObject::invokeMethod(m_audioProcessor, "requestSampleRate", Q_ARG(unsigned, rate)); + } } void GameController::setAudioChannelEnabled(int channel, bool enable) {

@@ -644,7 +657,9 @@ m_threadContext.fpsTarget = fps;

if (m_turbo && m_turboSpeed > 0) { m_threadContext.fpsTarget *= m_turboSpeed; } - redoSamples(m_audioProcessor->getBufferSamples()); + if (m_audioProcessor) { + redoSamples(m_audioProcessor->getBufferSamples()); + } threadContinue(); }

@@ -801,7 +816,9 @@ m_threadContext.fpsTarget = m_fpsTarget * m_turboSpeed;

m_threadContext.sync.audioWait = true; m_threadContext.sync.videoFrameWait = false; } - redoSamples(m_audioProcessor->getBufferSamples()); + if (m_audioProcessor) { + redoSamples(m_audioProcessor->getBufferSamples()); + } threadContinue(); }

@@ -830,11 +847,21 @@ }

#endif void GameController::reloadAudioDriver() { - QMetaObject::invokeMethod(m_audioProcessor, "pause", Qt::BlockingQueuedConnection); - int samples = m_audioProcessor->getBufferSamples(); - delete m_audioProcessor; + int samples = 0; + unsigned sampleRate = 0; + if (m_audioProcessor) { + QMetaObject::invokeMethod(m_audioProcessor, "pause", Qt::BlockingQueuedConnection); + samples = m_audioProcessor->getBufferSamples(); + sampleRate = m_audioProcessor->sampleRate(); + delete m_audioProcessor; + } m_audioProcessor = AudioProcessor::create(); - m_audioProcessor->setBufferSamples(samples); + if (samples) { + m_audioProcessor->setBufferSamples(samples); + } + if (sampleRate) { + m_audioProcessor->requestSampleRate(sampleRate); + } m_audioProcessor->moveToThread(m_audioThread); connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start())); connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
M src/platform/qt/GameController.hsrc/platform/qt/GameController.h

@@ -119,6 +119,7 @@ void keyPressed(int key);

void keyReleased(int key); void clearKeys(); void setAudioBufferSamples(int samples); + void setAudioSampleRate(unsigned rate); void setAudioChannelEnabled(int channel, bool enable = true); void setVideoLayerEnabled(int layer, bool enable = true); void setFPSTarget(float fps);
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -127,6 +127,7 @@ connect(this, SIGNAL(shutdown()), m_display, SLOT(stopDrawing()));

connect(this, SIGNAL(shutdown()), m_controller, SLOT(closeGame())); connect(this, SIGNAL(shutdown()), m_logView, SLOT(hide())); connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int))); + connect(this, SIGNAL(sampleRateChanged(unsigned)), m_controller, SLOT(setAudioSampleRate(unsigned))); connect(this, SIGNAL(fpsTargetChanged(float)), m_controller, SLOT(setFPSTarget(float))); connect(&m_fpsTimer, SIGNAL(timeout()), this, SLOT(showFPS())); connect(m_display, &Display::hideCursor, [this]() {

@@ -195,12 +196,17 @@ if (opts->bios) {

m_controller->loadBIOS(opts->bios); } + // TODO: Move these to ConfigController if (opts->fpsTarget) { emit fpsTargetChanged(opts->fpsTarget); } if (opts->audioBuffers) { emit audioBufferSamplesChanged(opts->audioBuffers); + } + + if (opts->sampleRate) { + emit sampleRateChanged(opts->sampleRate); } if (opts->width && opts->height) {
M src/platform/qt/Window.hsrc/platform/qt/Window.h

@@ -54,6 +54,7 @@ signals:

void startDrawing(GBAThread*); void shutdown(); void audioBufferSamplesChanged(int samples); + void sampleRateChanged(unsigned samples); void fpsTargetChanged(float target); public slots:
M src/platform/sdl/main.csrc/platform/sdl/main.c

@@ -112,6 +112,10 @@

bool didFail = false; renderer.audio.samples = context.audioBuffers; + renderer.audio.sampleRate = 44100; + if (opts.sampleRate) { + renderer.audio.sampleRate = opts.sampleRate; + } if (!GBASDLInitAudio(&renderer.audio, &context)) { didFail = true; }
M src/platform/sdl/sdl-audio.csrc/platform/sdl/sdl-audio.c

@@ -22,7 +22,7 @@ GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError());

return false; } - context->desiredSpec.freq = 44100; + context->desiredSpec.freq = context->sampleRate; context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.channels = 2; context->desiredSpec.samples = context->samples;
M src/platform/sdl/sdl-audio.hsrc/platform/sdl/sdl-audio.h

@@ -15,6 +15,7 @@

struct GBASDLAudio { // Input size_t samples; + unsigned sampleRate; // State SDL_AudioSpec desiredSpec;