mirror of https://github.com/mgba-emu/mgba.git
Audio rendering in Qt
This commit is contained in:
parent
8a82144ceb
commit
baeaf8729f
|
@ -0,0 +1,33 @@
|
|||
#include "AudioDevice.h"
|
||||
|
||||
extern "C" {
|
||||
#include "gba.h"
|
||||
#include "gba-audio.h"
|
||||
}
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
AudioDevice::AudioDevice(GBAAudio* audio, QObject* parent)
|
||||
: QIODevice(parent)
|
||||
, m_audio(audio)
|
||||
{
|
||||
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_audio->sampleRate * fudgeRate);
|
||||
}
|
||||
|
||||
qint64 AudioDevice::readData(char* data, qint64 maxSize) {
|
||||
if (maxSize > 0xFFFFFFFF) {
|
||||
maxSize = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return GBAAudioResampleNN(m_audio, m_ratio, &m_drift, reinterpret_cast<GBAStereoSample*>(data), maxSize / sizeof(GBAStereoSample)) * sizeof(GBAStereoSample);
|
||||
}
|
||||
|
||||
qint64 AudioDevice::writeData(const char*, qint64) {
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef QGBA_AUDIO_DEVICE
|
||||
#define QGBA_AUDIO_DEVICE
|
||||
|
||||
#include <QAudioFormat>
|
||||
#include <QIODevice>
|
||||
|
||||
struct GBAAudio;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class AudioDevice : public QIODevice {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioDevice(GBAAudio* audio, QObject* parent = 0);
|
||||
|
||||
void setFormat(const QAudioFormat& format);
|
||||
|
||||
protected:
|
||||
virtual qint64 readData(char* data, qint64 maxSize);
|
||||
virtual qint64 writeData(const char* data, qint64 maxSize);
|
||||
|
||||
private:
|
||||
GBAAudio* m_audio;
|
||||
float m_drift;
|
||||
float m_ratio;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -14,11 +14,11 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||
find_package(Qt5Widgets REQUIRED)
|
||||
|
||||
set(UI_FILES Window.ui)
|
||||
set(SOURCE_FILES Display.cpp GameController.cpp Window.cpp)
|
||||
set(SOURCE_FILES AudioDevice.cpp Display.cpp GameController.cpp Window.cpp)
|
||||
|
||||
qt5_wrap_ui(UI_HEADERS ${UI_FILES})
|
||||
|
||||
add_executable(QGBAc WIN32 MACOSX_BUNDLE ${UI_FILES} ${UI_HEADERS} main.cpp ${SOURCE_FILES})
|
||||
|
||||
qt5_use_modules(QGBAc Widgets OpenGL)
|
||||
qt5_use_modules(QGBAc Widgets Multimedia OpenGL)
|
||||
target_link_libraries(QGBAc ${OPENGL_LIBRARY} ${BINARY_NAME})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "GameController.h"
|
||||
|
||||
extern "C" {
|
||||
#include "gba.h"
|
||||
#include "renderers/video-software.h"
|
||||
}
|
||||
|
||||
|
@ -9,6 +10,7 @@ using namespace QGBA;
|
|||
GameController::GameController(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_drawContext(256, 256, QImage::Format_RGB32)
|
||||
, m_audioContext(0)
|
||||
{
|
||||
m_renderer = new GBAVideoSoftwareRenderer;
|
||||
GBAVideoSoftwareRendererCreate(m_renderer);
|
||||
|
@ -19,11 +21,14 @@ GameController::GameController(QObject* parent)
|
|||
m_threadContext.renderer = &m_renderer->d;
|
||||
m_threadContext.frameskip = 0;
|
||||
m_threadContext.sync.videoFrameWait = 0;
|
||||
m_threadContext.sync.audioWait = 0;
|
||||
m_threadContext.startCallback = 0;
|
||||
m_threadContext.sync.audioWait = 1;
|
||||
m_threadContext.startCallback = [] (GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
controller->setupAudio(&context->gba->audio);
|
||||
};
|
||||
m_threadContext.cleanCallback = 0;
|
||||
m_threadContext.frameCallback = [] (GBAThread* context) {
|
||||
GameController* controller = (GameController*) context->userData;
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
controller->frameAvailable(controller->m_drawContext);
|
||||
};
|
||||
m_threadContext.userData = this;
|
||||
|
@ -48,3 +53,12 @@ bool GameController::loadGame(const QString& path) {
|
|||
GBAThreadStart(&m_threadContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameController::setupAudio(GBAAudio* audio) {
|
||||
if (m_audioContext) {
|
||||
delete m_audioContext;
|
||||
}
|
||||
m_audioContext = new AudioDevice(audio);
|
||||
|
||||
emit audioDeviceAvailable(m_audioContext);
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "AudioDevice.h"
|
||||
|
||||
extern "C" {
|
||||
#include "gba-thread.h"
|
||||
}
|
||||
|
||||
struct GBAAudio;
|
||||
struct GBAVideoSoftwareRenderer;
|
||||
|
||||
namespace QGBA {
|
||||
|
@ -23,12 +26,16 @@ public:
|
|||
|
||||
signals:
|
||||
void frameAvailable(const QImage&);
|
||||
void audioDeviceAvailable(AudioDevice*);
|
||||
|
||||
public slots:
|
||||
bool loadGame(const QString& path);
|
||||
|
||||
private:
|
||||
void setupAudio(GBAAudio* audio);
|
||||
|
||||
QImage m_drawContext;
|
||||
AudioDevice* m_audioContext;
|
||||
GBAThread m_threadContext;
|
||||
GBAVideoSoftwareRenderer* m_renderer;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ Window::Window(QWidget* parent) : QMainWindow(parent) {
|
|||
m_display = new Display(this);
|
||||
setCentralWidget(m_display);
|
||||
connect(m_controller, SIGNAL(frameAvailable(const QImage&)), m_display, SLOT(draw(const QImage&)));
|
||||
connect(m_controller, SIGNAL(audioDeviceAvailable(AudioDevice*)), this, SLOT(setupAudio(AudioDevice*)));
|
||||
|
||||
connect(actionOpen, SIGNAL(triggered()), this, SLOT(selectROM()));
|
||||
}
|
||||
|
@ -21,3 +22,20 @@ void Window::selectROM() {
|
|||
m_controller->loadGame(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::setupAudio(AudioDevice* device) {
|
||||
if (!m_audio) {
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(44100);
|
||||
format.setChannelCount(2);
|
||||
format.setSampleSize(16);
|
||||
format.setCodec("audio/pcm");
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
|
||||
m_audio = new QAudioOutput(format, this);
|
||||
m_audio->setBufferSize(1024);
|
||||
}
|
||||
device->setFormat(m_audio->format());
|
||||
m_audio->start(device);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef QGBA_WINDOW
|
||||
#define QGBA_WINDOW
|
||||
|
||||
#include <QAudioOutput>
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "GameController.h"
|
||||
|
@ -19,7 +20,11 @@ public:
|
|||
public slots:
|
||||
void selectROM();
|
||||
|
||||
private slots:
|
||||
void setupAudio(AudioDevice*);
|
||||
|
||||
private:
|
||||
QAudioOutput* m_audio;
|
||||
GameController* m_controller;
|
||||
Display* m_display;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue