Qt: Use SDL audio, when available
Jeffrey Pfau jeffrey@endrift.com
Wed, 19 Nov 2014 23:14:44 -0800
11 files changed,
242 insertions(+),
92 deletions(-)
jump to
M
src/platform/qt/AudioProcessor.cpp
→
src/platform/qt/AudioProcessor.cpp
@@ -2,6 +2,12 @@ #include "AudioProcessor.h"
#include "AudioDevice.h" +#ifdef BUILD_SDL +#include "AudioProcessorSDL.h" +#else +#include "AudioProcessorQt.h" +#endif + #include <QAudioOutput> extern "C" {@@ -10,63 +16,19 @@ }
using namespace QGBA; +AudioProcessor* AudioProcessor::create() { +#ifdef BUILD_SDL + return new AudioProcessorSDL(); +#else + return new AudioProcessorQt(); +#endif +} + AudioProcessor::AudioProcessor(QObject* parent) : QObject(parent) - , m_audioOutput(nullptr) - , m_device(nullptr) { } void AudioProcessor::setInput(GBAThread* input) { m_context = input; - if (m_device) { - m_device->setInput(input); - if (m_audioOutput) { - m_device->setFormat(m_audioOutput->format()); - } - } -} - -void AudioProcessor::start() { - if (!m_device) { - m_device = new AudioDevice(this); - } - - if (!m_audioOutput) { - QAudioFormat format; - format.setSampleRate(44100); - format.setChannelCount(2); - format.setSampleSize(16); - format.setCodec("audio/pcm"); - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleType(QAudioFormat::SignedInt); - - m_audioOutput = new QAudioOutput(format, this); - } - - m_device->setInput(m_context); - m_device->setFormat(m_audioOutput->format()); - m_audioOutput->setBufferSize(m_context->audioBuffers * 4); - - m_audioOutput->start(m_device); -} - -void AudioProcessor::pause() { - if (m_audioOutput) { - m_audioOutput->stop(); - } -} - -void AudioProcessor::setBufferSamples(int samples) { - if (m_audioOutput) { - m_audioOutput->stop(); - m_audioOutput->setBufferSize(samples * 4); - m_audioOutput->start(m_device); - } -} - -void AudioProcessor::inputParametersChanged() { - if (m_device) { - m_device->setFormat(m_audioOutput->format()); - } }
M
src/platform/qt/AudioProcessor.h
→
src/platform/qt/AudioProcessor.h
@@ -4,31 +4,28 @@ #include <QObject>
struct GBAThread; -class QAudioOutput; - namespace QGBA { - -class AudioDevice; class AudioProcessor : public QObject { Q_OBJECT public: + static AudioProcessor* create(); AudioProcessor(QObject* parent = nullptr); - void setInput(GBAThread* input); + virtual void setInput(GBAThread* input); public slots: - void start(); - void pause(); + virtual void start() = 0; + virtual void pause() = 0; - void setBufferSamples(int samples); - void inputParametersChanged(); + virtual void setBufferSamples(int samples) = 0; + virtual void inputParametersChanged() = 0; +protected: + GBAThread* input() { return m_context; } private: GBAThread* m_context; - QAudioOutput* m_audioOutput; - AudioDevice* m_device; }; }
A
src/platform/qt/AudioProcessorQt.cpp
@@ -0,0 +1,72 @@
+#include "AudioProcessorQt.h" + +#include "AudioDevice.h" + +#include <QAudioOutput> + +extern "C" { +#include "gba-thread.h" +} + +using namespace QGBA; + +AudioProcessorQt::AudioProcessorQt(QObject* parent) + : AudioProcessor(parent) + , m_audioOutput(nullptr) + , m_device(nullptr) +{ +} + +void AudioProcessorQt::setInput(GBAThread* input) { + AudioProcessor::setInput(input); + if (m_device) { + m_device->setInput(input); + if (m_audioOutput) { + m_device->setFormat(m_audioOutput->format()); + } + } +} + +void AudioProcessorQt::start() { + if (!m_device) { + m_device = new AudioDevice(this); + } + + if (!m_audioOutput) { + QAudioFormat format; + format.setSampleRate(44100); + format.setChannelCount(2); + format.setSampleSize(16); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + + m_audioOutput = new QAudioOutput(format, this); + } + + m_device->setInput(input()); + m_device->setFormat(m_audioOutput->format()); + m_audioOutput->setBufferSize(input()->audioBuffers * 4); + + m_audioOutput->start(m_device); +} + +void AudioProcessorQt::pause() { + if (m_audioOutput) { + m_audioOutput->stop(); + } +} + +void AudioProcessorQt::setBufferSamples(int samples) { + if (m_audioOutput) { + m_audioOutput->stop(); + m_audioOutput->setBufferSize(samples * 4); + m_audioOutput->start(m_device); + } +} + +void AudioProcessorQt::inputParametersChanged() { + if (m_device) { + m_device->setFormat(m_audioOutput->format()); + } +}
A
src/platform/qt/AudioProcessorQt.h
@@ -0,0 +1,31 @@
+#ifndef QGBA_AUDIO_PROCESSOR_QT +#define QGBA_AUDIO_PROCESSOR_QT +#include "AudioProcessor.h" + +namespace QGBA { + +class AudioDevice; + +class AudioProcessorQt : public AudioProcessor { +Q_OBJECT + +public: + AudioProcessorQt(QObject* parent = nullptr); + + virtual void setInput(GBAThread* input); + +public slots: + virtual void start(); + virtual void pause(); + + virtual void setBufferSamples(int samples); + virtual void inputParametersChanged(); + +private: + QAudioOutput* m_audioOutput; + AudioDevice* m_device; +}; + +} + +#endif
A
src/platform/qt/AudioProcessorSDL.cpp
@@ -0,0 +1,41 @@
+#include "AudioProcessorSDL.h" + +extern "C" { +#include "gba-thread.h" +} + +using namespace QGBA; + +AudioProcessorSDL::AudioProcessorSDL(QObject* parent) + : AudioProcessor(parent) + , m_audio() +{ +} + +AudioProcessorSDL::~AudioProcessorSDL() { + GBASDLDeinitAudio(&m_audio); +} + +void AudioProcessorSDL::start() { + if (m_audio.thread) { + GBASDLResumeAudio(&m_audio); + } else { + m_audio.samples = input()->audioBuffers; + GBASDLInitAudio(&m_audio, input()); + } +} + +void AudioProcessorSDL::pause() { + GBASDLPauseAudio(&m_audio); +} + +void AudioProcessorSDL::setBufferSamples(int samples) { + if (m_audio.thread) { + GBASDLDeinitAudio(&m_audio); + m_audio.samples = samples; + GBASDLInitAudio(&m_audio, input()); + } +} + +void AudioProcessorSDL::inputParametersChanged() { +}
A
src/platform/qt/AudioProcessorSDL.h
@@ -0,0 +1,35 @@
+#ifndef QGBA_AUDIO_PROCESSOR_SDL +#define QGBA_AUDIO_PROCESSOR_SDL +#include "AudioProcessor.h" + +#ifdef BUILD_SDL + +extern "C" { +#include "platform/sdl/sdl-audio.h" +} + +namespace QGBA { + +class AudioProcessorSDL : public AudioProcessor { +Q_OBJECT + +public: + AudioProcessorSDL(QObject* parent = nullptr); + ~AudioProcessorSDL(); + +public slots: + virtual void start(); + virtual void pause(); + + virtual void setBufferSamples(int samples); + virtual void inputParametersChanged(); + +private: + GBASDLAudio m_audio; +}; + +} + +#endif + +#endif
M
src/platform/qt/CMakeLists.txt
→
src/platform/qt/CMakeLists.txt
@@ -11,7 +11,7 @@ if(SDL2_FOUND)
link_directories(${SDL2_LIBDIR}) endif() set(PLATFORM_LIBRARY "${PLATFORM_LIBRARY};${SDL_LIBRARY};${SDLMAIN_LIBRARY}") - set(PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-events.c) + set(PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-events.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-audio.c) include_directories(${SDL_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/src/platform/sdl) endif()@@ -23,7 +23,8 @@ find_package(Qt5OpenGL)
find_package(Qt5Widgets) find_package(OpenGL) -if(NOT Qt5Multimedia_FOUND OR NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND OR NOT OPENGL_FOUND) +if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND OR NOT OPENGL_FOUND) + message(WARNING "Cannot find Qt modules") set(BUILD_QT OFF PARENT_SCOPE) return() endif()@@ -52,6 +53,16 @@ LoadSaveState.ui
LogView.ui VideoView.ui) +if(BUILD_SDL) + list(APPEND SOURCE_FILES AudioProcessorSDL.cpp) +elseif(Qt5Multimedia_FOUND) + list(APPEND SOURCE_FILES AudioProcessorQt.cpp) +else() + message(WARNING "No supported audio modules found") + set(BUILD_QT OFF PARENT_SCOPE) + return() +endif() + if(USE_GDB_STUB) set(SOURCE_FILES ${PLATFORM_SRC} ${SOURCE_FILES} GDBController.cpp GDBWindow.cpp) endif()@@ -68,5 +79,8 @@ endif()
add_executable(mGBA WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR}/res/mgba.icns ${SOURCE_FILES} ${UI_FILES} ${RESOURCES}) set_target_properties(mGBA PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in) -qt5_use_modules(mGBA Widgets Multimedia OpenGL) +qt5_use_modules(mGBA Widgets OpenGL) +if(Qt5Multimedia_FOUND) + qt5_use_modules(mGBA Multimedia) +endif() target_link_libraries(mGBA ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY} ${BINARY_NAME} Qt5::Widgets)
M
src/platform/qt/GameController.cpp
→
src/platform/qt/GameController.cpp
@@ -22,7 +22,7 @@ , m_threadContext()
, m_activeKeys(0) , m_gameOpen(false) , m_audioThread(new QThread(this)) - , m_audioProcessor(new AudioProcessor) + , m_audioProcessor(AudioProcessor::create()) , m_videoSync(VIDEO_SYNC) , m_audioSync(AUDIO_SYNC) , m_turbo(false)
M
src/platform/sdl/main.c
→
src/platform/sdl/main.c
@@ -81,8 +81,6 @@ }
struct GBAThread context = { .renderer = &renderer.d.d, - .startCallback = _GBASDLStart, - .cleanCallback = _GBASDLClean, .userData = &renderer };@@ -92,10 +90,7 @@ GBAMapOptionsToContext(&opts, &context);
GBAMapArgumentsToContext(&args, &context); renderer.audio.samples = context.audioBuffers; - GBASDLInitAudio(&renderer.audio); - if (renderer.audio.samples > context.audioBuffers) { - context.audioBuffers = renderer.audio.samples * 2; - } + GBASDLInitAudio(&renderer.audio, &context); renderer.events.bindings = &inputMap; GBASDLInitBindings(&inputMap);@@ -140,14 +135,3 @@
SDL_Quit(); } - -static void _GBASDLStart(struct GBAThread* threadContext) { - struct SDLSoftwareRenderer* renderer = threadContext->userData; - renderer->audio.audio = &threadContext->gba->audio; - renderer->audio.thread = threadContext; -} - -static void _GBASDLClean(struct GBAThread* threadContext) { - struct SDLSoftwareRenderer* renderer = threadContext->userData; - renderer->audio.audio = 0; -}
M
src/platform/sdl/sdl-audio.c
→
src/platform/sdl/sdl-audio.c
@@ -7,7 +7,7 @@ #define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2)
static void _GBASDLAudioCallback(void* context, Uint8* data, int len); -bool GBASDLInitAudio(struct GBASDLAudio* context) { +bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system"); return false;@@ -19,14 +19,17 @@ context->desiredSpec.channels = 2;
context->desiredSpec.samples = context->samples; context->desiredSpec.callback = _GBASDLAudioCallback; context->desiredSpec.userdata = context; - context->audio = 0; - context->thread = 0; context->drift = 0.f; if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system"); return false; } + context->thread = threadContext; context->samples = context->obtainedSpec.samples; + if (context->samples > threadContext->audioBuffers) { + threadContext->audioBuffers = context->samples * 2; + } + SDL_PauseAudio(0); return true; }@@ -38,16 +41,26 @@ SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO); } +void GBASDLPauseAudio(struct GBASDLAudio* context) { + UNUSED(context); + SDL_PauseAudio(1); +} + +void GBASDLResumeAudio(struct GBASDLAudio* context) { + UNUSED(context); + SDL_PauseAudio(0); +} + static void _GBASDLAudioCallback(void* context, Uint8* data, int len) { struct GBASDLAudio* audioContext = context; - if (!context || !audioContext->audio) { + if (!context || !audioContext->thread) { memset(data, 0, len); return; } - audioContext->ratio = GBAAudioCalculateRatio(audioContext->audio, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq); + audioContext->ratio = GBAAudioCalculateRatio(&audioContext->thread->gba->audio, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq); struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; len /= 2 * audioContext->obtainedSpec.channels; if (audioContext->obtainedSpec.channels == 2) { - GBAAudioResampleNN(audioContext->audio, audioContext->ratio, &audioContext->drift, ssamples, len); + GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len); } }
M
src/platform/sdl/sdl-audio.h
→
src/platform/sdl/sdl-audio.h
@@ -15,11 +15,12 @@ SDL_AudioSpec obtainedSpec;
float drift; float ratio; - struct GBAAudio* audio; struct GBAThread* thread; }; -bool GBASDLInitAudio(struct GBASDLAudio* context); +bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext); void GBASDLDeinitAudio(struct GBASDLAudio* context); +void GBASDLPauseAudio(struct GBASDLAudio* context); +void GBASDLResumeAudio(struct GBASDLAudio* context); #endif