mirror of https://github.com/mgba-emu/mgba.git
Move AudioThread into AudioProcessor, run in its own thread
This commit is contained in:
parent
d5c0dffb29
commit
62f6471c0d
|
@ -8,17 +8,23 @@ extern "C" {
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
AudioDevice::AudioDevice(GBAThread* threadContext, QObject* parent)
|
||||
AudioDevice::AudioDevice(QObject* parent)
|
||||
: QIODevice(parent)
|
||||
, m_context(threadContext)
|
||||
, m_context(nullptr)
|
||||
{
|
||||
setOpenMode(ReadOnly);
|
||||
}
|
||||
|
||||
void AudioDevice::setFormat(const QAudioFormat& format) {
|
||||
// TODO: merge where the fudge rate exists
|
||||
float fudgeRate = 16853760.0f / GBA_ARM7TDMI_FREQUENCY;
|
||||
m_ratio = format.sampleRate() / (float) (m_context->gba->audio.sampleRate * fudgeRate);
|
||||
if (!GBAThreadHasStarted(m_context)) {
|
||||
return;
|
||||
}
|
||||
// TODO: make this thread-safe
|
||||
m_ratio = GBAAudioCalculateRatio(&m_context->gba->audio, 60, format.sampleRate());
|
||||
}
|
||||
|
||||
void AudioDevice::setInput(GBAThread* input) {
|
||||
m_context = input;
|
||||
}
|
||||
|
||||
qint64 AudioDevice::readData(char* data, qint64 maxSize) {
|
||||
|
@ -36,53 +42,3 @@ qint64 AudioDevice::readData(char* data, qint64 maxSize) {
|
|||
qint64 AudioDevice::writeData(const char*, qint64) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioThread::AudioThread(QObject* parent)
|
||||
: QThread(parent)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void AudioThread::setInput(GBAThread* input) {
|
||||
m_input = input;
|
||||
}
|
||||
|
||||
void AudioThread::shutdown() {
|
||||
disconnect();
|
||||
if (m_audioOutput) {
|
||||
m_audioOutput->stop();
|
||||
delete m_audioOutput;
|
||||
m_audioOutput = nullptr;
|
||||
}
|
||||
if (m_device) {
|
||||
delete m_device;
|
||||
m_device = nullptr;
|
||||
}
|
||||
quit();
|
||||
}
|
||||
|
||||
void AudioThread::pause() {
|
||||
m_audioOutput->stop();
|
||||
}
|
||||
|
||||
void AudioThread::resume() {
|
||||
m_audioOutput->start(m_device);
|
||||
}
|
||||
|
||||
void AudioThread::run() {
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(44100);
|
||||
format.setChannelCount(2);
|
||||
format.setSampleSize(16);
|
||||
format.setCodec("audio/pcm");
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
|
||||
m_device = new AudioDevice(m_input);
|
||||
m_audioOutput = new QAudioOutput(format);
|
||||
m_audioOutput->setBufferSize(1024);
|
||||
m_device->setFormat(m_audioOutput->format());
|
||||
m_audioOutput->start(m_device);
|
||||
|
||||
exec();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#ifndef QGBA_AUDIO_DEVICE
|
||||
#define QGBA_AUDIO_DEVICE
|
||||
|
||||
#include <QAudioFormat>
|
||||
#include <QAudioOutput>
|
||||
#include <QIODevice>
|
||||
#include <QThread>
|
||||
|
||||
struct GBAThread;
|
||||
|
||||
|
@ -14,8 +11,9 @@ class AudioDevice : public QIODevice {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioDevice(GBAThread* threadContext, QObject* parent = nullptr);
|
||||
AudioDevice(QObject* parent = nullptr);
|
||||
|
||||
void setInput(GBAThread* input);
|
||||
void setFormat(const QAudioFormat& format);
|
||||
|
||||
protected:
|
||||
|
@ -28,28 +26,6 @@ private:
|
|||
float m_ratio;
|
||||
};
|
||||
|
||||
class AudioThread : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioThread(QObject* parent = nullptr);
|
||||
|
||||
void setInput(GBAThread* input);
|
||||
|
||||
public slots:
|
||||
void shutdown();
|
||||
void pause();
|
||||
void resume();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
private:
|
||||
GBAThread* m_input;
|
||||
QAudioOutput* m_audioOutput;
|
||||
AudioDevice* m_device;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#include "AudioProcessor.h"
|
||||
|
||||
#include "AudioDevice.h"
|
||||
|
||||
#include <QAudioOutput>
|
||||
|
||||
extern "C" {
|
||||
#include "gba-thread.h"
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
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());
|
||||
|
||||
assert(m_audioOutput->thread() == thread());
|
||||
m_audioOutput->start(m_device);
|
||||
}
|
||||
|
||||
void AudioProcessor::pause() {
|
||||
m_audioOutput->stop();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef QGBA_AUDIO_PROCESSOR
|
||||
#define QGBA_AUDIO_PROCESSOR
|
||||
#include <QObject>
|
||||
|
||||
struct GBAThread;
|
||||
|
||||
class QAudioOutput;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class AudioDevice;
|
||||
|
||||
class AudioProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioProcessor(QObject* parent = nullptr);
|
||||
|
||||
void setInput(GBAThread* input);
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void pause();
|
||||
|
||||
private:
|
||||
GBAThread* m_context;
|
||||
QAudioOutput* m_audioOutput;
|
||||
AudioDevice* m_device;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -21,7 +21,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
set(SOURCE_FILES AudioDevice.cpp Display.cpp GameController.cpp Window.cpp)
|
||||
set(SOURCE_FILES AudioDevice.cpp AudioProcessor.cpp Display.cpp GameController.cpp Window.cpp)
|
||||
|
||||
if(USE_GDB_STUB)
|
||||
set(SOURCE_FILES ${PLATFORM_SRC} ${SOURCE_FILES} GDBController.cpp GDBWindow.cpp)
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#include "GameController.h"
|
||||
|
||||
#include "AudioProcessor.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
extern "C" {
|
||||
#include "gba.h"
|
||||
#include "gba-audio.h"
|
||||
#include "renderers/video-software.h"
|
||||
#include "util/vfs.h"
|
||||
}
|
||||
|
@ -13,6 +18,8 @@ GameController::GameController(QObject* parent)
|
|||
, m_drawContext(new uint32_t[256 * 256])
|
||||
, m_activeKeys(0)
|
||||
, m_rom(nullptr)
|
||||
, m_audioThread(new QThread(this))
|
||||
, m_audioProcessor(new AudioProcessor)
|
||||
{
|
||||
#ifdef BUILD_SDL
|
||||
SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
|
||||
|
@ -34,6 +41,7 @@ GameController::GameController(QObject* parent)
|
|||
};
|
||||
m_threadContext.startCallback = [] (GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
controller->m_audioProcessor->setInput(context);
|
||||
controller->gameStarted(context);
|
||||
};
|
||||
|
||||
|
@ -53,12 +61,18 @@ GameController::GameController(QObject* parent)
|
|||
controller->frameAvailable(controller->m_drawContext);
|
||||
};
|
||||
|
||||
m_audioThread->start();
|
||||
m_audioProcessor->moveToThread(m_audioThread);
|
||||
connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start()));
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(testSDLEvents()));
|
||||
#endif
|
||||
}
|
||||
|
||||
GameController::~GameController() {
|
||||
m_audioProcessor->pause();
|
||||
m_audioThread->quit();
|
||||
if (GBAThreadIsPaused(&m_threadContext)) {
|
||||
GBAThreadUnpause(&m_threadContext);
|
||||
}
|
||||
|
@ -98,6 +112,7 @@ void GameController::loadGame(const QString& path) {
|
|||
|
||||
m_threadContext.rom = VFileFromFD(m_rom->handle());
|
||||
m_threadContext.fname = path.toLocal8Bit().constData();
|
||||
|
||||
GBAThreadStart(&m_threadContext);
|
||||
}
|
||||
|
||||
|
@ -125,7 +140,9 @@ void GameController::setPaused(bool paused) {
|
|||
}
|
||||
if (paused) {
|
||||
GBAThreadPause(&m_threadContext);
|
||||
m_audioProcessor->pause();
|
||||
} else {
|
||||
m_audioProcessor->start();
|
||||
GBAThreadUnpause(&m_threadContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ extern "C" {
|
|||
struct GBAAudio;
|
||||
struct GBAVideoSoftwareRenderer;
|
||||
|
||||
class QThread;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class AudioDevice;
|
||||
class AudioProcessor;
|
||||
|
||||
class GameController : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -70,6 +72,9 @@ private:
|
|||
QFile* m_rom;
|
||||
QFile* m_bios;
|
||||
|
||||
QThread* m_audioThread;
|
||||
AudioProcessor* m_audioProcessor;
|
||||
|
||||
QMutex m_pauseMutex;
|
||||
bool m_pauseAfterFrame;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include <QKeySequence>
|
||||
#include <QMenuBar>
|
||||
|
||||
#include "AudioDevice.h"
|
||||
#include "GameController.h"
|
||||
#include "GDBWindow.h"
|
||||
#include "GDBController.h"
|
||||
|
@ -14,7 +13,6 @@ using namespace QGBA;
|
|||
|
||||
Window::Window(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, m_audioThread(nullptr)
|
||||
#ifdef USE_GDB_STUB
|
||||
, m_gdbController(nullptr)
|
||||
#endif
|
||||
|
@ -126,21 +124,12 @@ void Window::gameStarted(GBAThread* context) {
|
|||
foreach (QAction* action, m_gameActions) {
|
||||
action->setDisabled(false);
|
||||
}
|
||||
if (!m_audioThread) {
|
||||
m_audioThread = new AudioThread(this);
|
||||
connect(this, SIGNAL(shutdown()), m_audioThread, SLOT(shutdown()));
|
||||
m_audioThread->setInput(context);
|
||||
m_audioThread->start(QThread::HighPriority);
|
||||
} else {
|
||||
m_audioThread->resume();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::gameStopped() {
|
||||
foreach (QAction* action, m_gameActions) {
|
||||
action->setDisabled(true);
|
||||
}
|
||||
m_audioThread->pause();
|
||||
}
|
||||
|
||||
void Window::setupMenu(QMenuBar* menubar) {
|
||||
|
|
|
@ -12,7 +12,6 @@ extern "C" {
|
|||
|
||||
namespace QGBA {
|
||||
|
||||
class AudioThread;
|
||||
class GameController;
|
||||
class GDBController;
|
||||
|
||||
|
@ -47,7 +46,6 @@ private:
|
|||
void setupMenu(QMenuBar*);
|
||||
GameController* m_controller;
|
||||
Display* m_display;
|
||||
AudioThread* m_audioThread;
|
||||
QList<QAction*> m_gameActions;
|
||||
|
||||
#ifdef USE_GDB_STUB
|
||||
|
|
Loading…
Reference in New Issue