GBA: Add GBACore

This commit is contained in:
Jeffrey Pfau 2016-02-04 00:49:45 -08:00
parent 28268a601b
commit 33a4c45f3f
14 changed files with 324 additions and 138 deletions

View File

@ -23,6 +23,7 @@ typedef uint32_t color_t;
#define BYTES_PER_PIXEL 4
#endif
struct blip_t;
struct mCoreSync;
struct mCore {
void* cpu;
@ -40,6 +41,8 @@ struct mCore {
void (*desiredVideoDimensions)(struct mCore*, unsigned* width, unsigned* height);
void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride);
struct blip_t* (*getAudioChannel)(struct mCore*, int ch);
bool (*isROM)(struct VFile* vf);
bool (*loadROM)(struct mCore*, struct VFile* vf);
bool (*loadSave)(struct mCore*, struct VFile* vf);

View File

@ -72,6 +72,18 @@ static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t st
gbcore->renderer.outputBufferStride = stride;
}
static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) {
struct GB* gb = core->board;
switch (ch) {
case 0:
return gb->audio.left;
case 1:
return gb->audio.right;
default:
return NULL;
}
}
static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
return GBLoadROM(core->board, vf);
}
@ -158,6 +170,7 @@ struct mCore* GBCoreCreate(void) {
core->setSync = _GBCoreSetSync;
core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
core->setVideoBuffer = _GBCoreSetVideoBuffer;
core->getAudioChannel = _GBCoreGetAudioChannel;
core->isROM = GBIsROM;
core->loadROM = _GBCoreLoadROM;
core->loadSave = _GBCoreLoadSave;

192
src/gba/core.c Normal file
View File

@ -0,0 +1,192 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "core.h"
#include "core/core.h"
#include "core/log.h"
#include "gba/gba.h"
#include "gba/renderers/video-software.h"
#include "util/memory.h"
struct GBACore {
struct mCore d;
struct GBAVideoSoftwareRenderer renderer;
int keys;
};
static bool _GBACoreInit(struct mCore* core) {
struct GBACore* gbacore = (struct GBACore*) core;
struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
if (!cpu || !gba) {
free(cpu);
free(gba);
return false;
}
core->cpu = cpu;
core->board = gba;
GBACreate(gba);
// TODO: Restore debugger and cheats
ARMSetComponents(cpu, &gba->d, 0, 0);
ARMInit(cpu);
GBAVideoSoftwareRendererCreate(&gbacore->renderer);
GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
gba->keySource = &gbacore->keys;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetInit(&core->dirs);
#endif
return true;
}
static void _GBACoreDeinit(struct mCore* core) {
ARMDeinit(core->cpu);
GBADestroy(core->board);
mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
mappedMemoryFree(core->board, sizeof(struct GBA));
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetDeinit(&core->dirs);
#endif
}
static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
struct GBA* gba = core->board;
gba->sync = sync;
}
static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
UNUSED(core);
*width = VIDEO_HORIZONTAL_PIXELS;
*height = VIDEO_VERTICAL_PIXELS;
}
static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->renderer.outputBuffer = buffer;
gbacore->renderer.outputBufferStride = stride;
}
static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
struct GBA* gba = core->board;
switch (ch) {
case 0:
return gba->audio.psg.left;
case 1:
return gba->audio.psg.right;
default:
return NULL;
}
}
static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
return GBALoadROM2(core->board, vf);
}
static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
return GBALoadSave(core->board, vf);
}
static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
// TODO
UNUSED(core);
UNUSED(vf);
mLOG(GBA, STUB, "Patches are not yet supported");
return false;
}
static void _GBACoreUnloadROM(struct mCore* core) {
return GBAUnloadROM(core->board);
}
static void _GBACoreReset(struct mCore* core) {
ARMReset(core->cpu);
}
static void _GBACoreRunFrame(struct mCore* core) {
struct GBA* gba = core->board;
int32_t frameCounter = gba->video.frameCounter;
while (gba->video.frameCounter == frameCounter) {
ARMRunLoop(core->cpu);
}
}
static void _GBACoreRunLoop(struct mCore* core) {
ARMRunLoop(core->cpu);
}
static void _GBACoreStep(struct mCore* core) {
ARMRun(core->cpu);
}
static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys = keys;
}
static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys |= keys;
}
static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys &= ~keys;
}
static int32_t _GBACoreFrameCounter(struct mCore* core) {
struct GBA* gba = core->board;
return gba->video.frameCounter;
}
static int32_t _GBACoreFrameCycles(struct mCore* core) {
UNUSED(core);
return VIDEO_TOTAL_LENGTH;
}
static int32_t _GBACoreFrequency(struct mCore* core) {
UNUSED(core);
return GBA_ARM7TDMI_FREQUENCY;
}
static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
struct GBA* gba = core->board;
gba->rtcSource = rtc;
}
struct mCore* GBACoreCreate(void) {
struct GBACore* gbacore = malloc(sizeof(*gbacore));
struct mCore* core = &gbacore->d;
core->cpu = 0;
core->board = 0;
core->init = _GBACoreInit;
core->deinit = _GBACoreDeinit;
core->setSync = _GBACoreSetSync;
core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
core->setVideoBuffer = _GBACoreSetVideoBuffer;
core->getAudioChannel = _GBACoreGetAudioChannel;
core->isROM = GBAIsROM;
core->loadROM = _GBACoreLoadROM;
core->loadSave = _GBACoreLoadSave;
core->loadPatch = _GBACoreLoadPatch;
core->unloadROM = _GBACoreUnloadROM;
core->reset = _GBACoreReset;
core->runFrame = _GBACoreRunFrame;
core->runLoop = _GBACoreRunLoop;
core->step = _GBACoreStep;
core->setKeys = _GBACoreSetKeys;
core->addKeys = _GBACoreAddKeys;
core->clearKeys = _GBACoreClearKeys;
core->frameCounter = _GBACoreFrameCounter;
core->frameCycles = _GBACoreFrameCycles;
core->frequency = _GBACoreFrequency;
core->setRTC = _GBACoreSetRTC;
return core;
}

12
src/gba/core.h Normal file
View File

@ -0,0 +1,12 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GBA_CORE_H
#define GBA_CORE_H
struct mCore;
struct mCore* GBACoreCreate(void);
#endif

View File

@ -22,6 +22,8 @@
#include "util/patch.h"
#include "util/vfs.h"
mLOG_DEFINE_CATEGORY(GBA, "GBA");
const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000;
const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
@ -443,7 +445,7 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf, const char* fname) {
return true;
}
bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) {
bool GBALoadROM2(struct GBA* gba, struct VFile* vf) {
GBAUnloadROM(gba);
gba->romVf = vf;
gba->pristineRomSize = vf->size(vf);
@ -466,14 +468,26 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char
}
gba->yankedRomSize = 0;
gba->memory.rom = gba->pristineRom;
gba->activeFile = fname;
gba->memory.romSize = gba->pristineRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
GBASavedataInit(&gba->memory.savedata, sav);
GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
return true;
// TODO: error check
return true;
}
bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) {
if (!GBALoadROM2(gba, vf)) {
return false;
}
gba->activeFile = fname;
GBALoadSave(gba, sav);
return true;
}
bool GBALoadSave(struct GBA* gba, struct VFile* sav) {
GBASavedataInit(&gba->memory.savedata, sav);
return true;
}
void GBAYankROM(struct GBA* gba) {

View File

@ -8,7 +8,8 @@
#include "util/common.h"
#include "arm.h"
#include "arm/arm.h"
#include "core/log.h"
#include "debugger/debugger.h"
#include "gba/interface.h"
@ -59,6 +60,8 @@ struct GBAThread;
struct Patch;
struct VFile;
mLOG_DECLARE_CATEGORY(GBA);
DECL_BITFIELD(GBATimerFlags, uint32_t);
DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4);
DECL_BIT(GBATimerFlags, CountUp, 4);
@ -171,6 +174,8 @@ void GBASetBreakpoint(struct GBA* gba, struct ARMComponent* component, uint32_t
void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname);
bool GBALoadROM2(struct GBA* gba, struct VFile* vf);
bool GBALoadSave(struct GBA* gba, struct VFile* sav);
void GBAYankROM(struct GBA* gba);
void GBAUnloadROM(struct GBA* gba);
void GBALoadBIOS(struct GBA* gba, struct VFile* vf);

View File

@ -20,7 +20,7 @@ AudioProcessorSDL::AudioProcessorSDL(QObject* parent)
}
AudioProcessorSDL::~AudioProcessorSDL() {
GBSDLDeinitAudio(&m_audio);
mSDLDeinitAudio(&m_audio);
}
bool AudioProcessorSDL::start() {
@ -30,26 +30,26 @@ bool AudioProcessorSDL::start() {
}
if (m_audio.thread) {
GBSDLResumeAudio(&m_audio);
mSDLResumeAudio(&m_audio);
return true;
} else {
if (!m_audio.samples) {
m_audio.samples = input()->audioBuffers;
}
return GBSDLInitAudio(&m_audio, input());
return mSDLInitAudio(&m_audio, input());
}
}
void AudioProcessorSDL::pause() {
GBSDLPauseAudio(&m_audio);
mSDLPauseAudio(&m_audio);
}
void AudioProcessorSDL::setBufferSamples(int samples) {
AudioProcessor::setBufferSamples(samples);
m_audio.samples = samples;
if (m_audio.thread) {
GBSDLDeinitAudio(&m_audio);
GBSDLInitAudio(&m_audio, input());
mSDLDeinitAudio(&m_audio);
mSDLInitAudio(&m_audio, input());
}
}
@ -59,8 +59,8 @@ void AudioProcessorSDL::inputParametersChanged() {
void AudioProcessorSDL::requestSampleRate(unsigned rate) {
m_audio.sampleRate = rate;
if (m_audio.thread) {
GBSDLDeinitAudio(&m_audio);
GBSDLInitAudio(&m_audio, input());
mSDLDeinitAudio(&m_audio);
mSDLInitAudio(&m_audio, input());
}
}

View File

@ -34,7 +34,7 @@ public slots:
virtual void requestSampleRate(unsigned) override;
private:
GBSDLAudio m_audio;
mSDLAudio m_audio;
};
}

View File

@ -70,7 +70,7 @@ endif()
if(BUILD_PANDORA)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/pandora-sdl.c)
else()
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
#list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
if(BUILD_GL)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)

View File

@ -8,13 +8,7 @@
#include "gl-common.h"
#include "core/core.h"
#ifdef M_CORE_GBA
#include "gba/supervisor/thread.h"
#endif
#ifdef M_CORE_GB
#include "gb/core.h"
#include "gb/gb.h"
#endif
#include "core/thread.h"
#include "platform/opengl/gl.h"
#define GB_GBA_CENTER ((VIDEO_HORIZONTAL_PIXELS - GB_VIDEO_HORIZONTAL_PIXELS + VIDEO_HORIZONTAL_PIXELS * (VIDEO_VERTICAL_PIXELS - GB_VIDEO_VERTICAL_PIXELS)) / 2)
@ -27,28 +21,32 @@ static void _doViewport(int w, int h, struct VideoBackend* v) {
}
#ifdef M_CORE_GBA
#include "gba/gba.h"
static bool mSDLGLInitGBA(struct mSDLRenderer* renderer);
static void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user);
static void mSDLGLDeinitGBA(struct mSDLRenderer* renderer);
#endif
#ifdef M_CORE_GB
#include "gb/gb.h"
static bool mSDLGLInitGB(struct mSDLRenderer* renderer);
static void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user);
static void mSDLGLDeinitGB(struct mSDLRenderer* renderer);
#endif
static void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user);
static void mSDLGLDeinit(struct mSDLRenderer* renderer);
#ifdef M_CORE_GBA
void mSDLGLCreate(struct mSDLRenderer* renderer) {
void mSDLGLCreateGBA(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLInitGBA;
renderer->deinit = mSDLGLDeinitGBA;
renderer->runloop = mSDLGLRunloopGBA;
renderer->deinit = mSDLGLDeinit;
renderer->runloop = mSDLGLRunloop;
}
bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer);
renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
renderer->outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
memset(renderer->outputBuffer, 0, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, VIDEO_HORIZONTAL_PIXELS);
GBAGLContextCreate(&renderer->gl);
renderer->gl.d.user = renderer;
@ -60,53 +58,13 @@ bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true;
}
void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user) {
struct GBAThread* context = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl.d;
renderer->audio.psg = &context->gba->audio.psg;
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
mSDLHandleEventGBA(context, &renderer->player, &event);
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Event handling can change the size of the screen
if (renderer->player.windowUpdated) {
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
renderer->player.windowUpdated = 0;
}
#endif
}
if (mCoreSyncWaitFrameStart(&context->sync)) {
v->postFrame(v, renderer->d.outputBuffer);
}
mCoreSyncWaitFrameEnd(&context->sync);
v->drawFrame(v);
v->swap(v);
}
renderer->audio.psg = 0;
}
void mSDLGLDeinitGBA(struct mSDLRenderer* renderer) {
if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d);
}
free(renderer->d.outputBuffer);
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_DeleteContext(renderer->glCtx);
#endif
}
#endif
#ifdef M_CORE_GB
void mSDLGLCreateGB(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLInitGB;
renderer->deinit = mSDLGLDeinitGB;
renderer->runloop = mSDLGLRunloopGB;
renderer->deinit = mSDLGLDeinit;
renderer->runloop = mSDLGLRunloop;
}
bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
@ -127,12 +85,12 @@ bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true;
}
#endif
void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) {
void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
struct mCoreThread* context = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl.d;
renderer->audio.psg = &((struct GB*) renderer->core->board)->audio;
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
@ -154,10 +112,9 @@ void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) {
v->drawFrame(v);
v->swap(v);
}
renderer->audio.psg = 0;
}
void mSDLGLDeinitGB(struct mSDLRenderer* renderer) {
void mSDLGLDeinit(struct mSDLRenderer* renderer) {
if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d);
}
@ -166,4 +123,3 @@ void mSDLGLDeinitGB(struct mSDLRenderer* renderer) {
SDL_GL_DeleteContext(renderer->glCtx);
#endif
}
#endif

View File

@ -15,8 +15,11 @@
#include "core/core.h"
#include "core/config.h"
#include "core/input.h"
#include "core/thread.h"
#include "gba/input.h"
#ifdef M_CORE_GBA
#include "gba/core.h"
#include "gba/gba.h"
#include "gba/supervisor/thread.h"
#include "gba/video.h"
@ -52,9 +55,7 @@ static void mSDLDeinit(struct mSDLRenderer* renderer);
#ifdef M_CORE_GBA
static int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct mCoreConfig* config);
#endif
#ifdef M_CORE_GB
static int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args);
#endif
static int mSDLRun(struct mSDLRenderer* renderer, struct GBAArguments* args);
int main(int argc, char** argv) {
@ -119,9 +120,9 @@ int main(int argc, char** argv) {
if (!opts.height) {
opts.height = VIDEO_VERTICAL_PIXELS;
}
GBAVideoSoftwareRendererCreate(&renderer.d);
renderer.core = GBACoreCreate();
#ifdef BUILD_GL
mSDLGLCreate(&renderer);
mSDLGLCreateGBA(&renderer);
#elif defined(BUILD_GLES2) || defined(USE_EPOXY)
mSDLGLES2Create(&renderer);
#else
@ -149,7 +150,7 @@ int main(int argc, char** argv) {
}
#endif
else {
printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n");
printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
freeArguments(&args);
mCoreConfigFreeOpts(&opts);
mCoreConfigDeinit(&config);
@ -197,17 +198,8 @@ int main(int argc, char** argv) {
int ret;
switch (platform) {
case PLATFORM_GBA:
ret = mSDLRunGBA(&renderer, &args, &opts, &config);
break;
case PLATFORM_GB:
ret = mSDLRunGB(&renderer, &args);
break;
default:
ret = 1;
break;
}
// TODO: Use opts and config
ret = mSDLRun(&renderer, &args);
mSDLDetachPlayer(&renderer.events, &renderer.player);
mInputMapDeinit(&inputMap);
@ -223,7 +215,6 @@ int main(int argc, char** argv) {
#ifdef M_CORE_GBA
int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct mCoreConfig* config) {
struct GBAThread context = {
.renderer = &renderer->d.d,
.userData = renderer
};
@ -240,7 +231,7 @@ int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct
if (opts->sampleRate) {
renderer->audio.sampleRate = opts->sampleRate;
}
if (!GBSDLInitAudio(&renderer->audio, &context)) {
if (!mSDLInitAudio(&renderer->audio, &context)) {
didFail = true;
}
@ -250,9 +241,7 @@ int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct
mSDLSuspendScreensaver(&renderer->events);
#endif
if (GBAThreadStart(&context)) {
renderer->audio.psg = &context.gba->audio.psg;
renderer->runloop(renderer, &context);
renderer->audio.psg = 0;
GBAThreadJoin(&context);
} else {
didFail = true;
@ -276,8 +265,7 @@ int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct
}
#endif
#ifdef M_CORE_GB
int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
int mSDLRun(struct mSDLRenderer* renderer, struct GBAArguments* args) {
struct mCoreThread thread = {
.core = renderer->core,
.sync = {
@ -292,18 +280,18 @@ int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
renderer->audio.samples = 1024;
renderer->audio.sampleRate = 44100;
bool didFail = !GBSDLInitAudio(&renderer->audio, 0);
bool didFail = !mSDLInitAudio(&renderer->audio, 0);
if (!didFail) {
renderer->audio.core = renderer->core;
renderer->audio.sync = &thread.sync;
if (mCoreThreadStart(&thread)) {
renderer->audio.psg = 0;
GBSDLResumeAudio(&renderer->audio);
mSDLResumeAudio(&renderer->audio);
renderer->runloop(renderer, &thread);
mCoreThreadJoin(&thread);
} else {
didFail = true;
printf("Could not run game. Are you sure the file exists and is a Game Boy game?\n");
printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
}
if (mCoreThreadHasCrashed(&thread)) {
@ -314,7 +302,6 @@ int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
renderer->core->unloadROM(renderer->core);
return didFail;
}
#endif
static bool mSDLInit(struct mSDLRenderer* renderer) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
@ -327,7 +314,7 @@ static bool mSDLInit(struct mSDLRenderer* renderer) {
static void mSDLDeinit(struct mSDLRenderer* renderer) {
mSDLDeinitEvents(&renderer->events);
GBSDLDeinitAudio(&renderer->audio);
mSDLDeinitAudio(&renderer->audio);
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_DestroyWindow(renderer->window);
#endif

View File

@ -44,11 +44,8 @@ struct mCore;
struct mSDLRenderer {
struct mCore* core;
color_t* outputBuffer;
#ifdef M_CORE_GBA
// TODO: Remove
struct GBAVideoSoftwareRenderer d;
#endif
struct GBSDLAudio audio;
struct mSDLAudio audio;
struct mSDLEvents events;
struct mSDLPlayer player;
@ -101,7 +98,7 @@ struct mSDLRenderer {
void mSDLSWCreate(struct mSDLRenderer* renderer);
#ifdef BUILD_GL
void mSDLGLCreate(struct mSDLRenderer* renderer);
void mSDLGLCreateGBA(struct mSDLRenderer* renderer);
void mSDLGLCreateGB(struct mSDLRenderer* renderer);
#endif

View File

@ -12,9 +12,9 @@
#define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2)
static void _GBSDLAudioCallback(void* context, Uint8* data, int len);
static void _mSDLAudioCallback(void* context, Uint8* data, int len);
bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext) {
bool mSDLInitAudio(struct mSDLAudio* context, struct GBAThread* threadContext) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError());
return false;
@ -24,7 +24,7 @@ bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext)
context->desiredSpec.format = AUDIO_S16SYS;
context->desiredSpec.channels = 2;
context->desiredSpec.samples = context->samples;
context->desiredSpec.callback = _GBSDLAudioCallback;
context->desiredSpec.callback = _mSDLAudioCallback;
context->desiredSpec.userdata = context;
#if SDL_VERSION_ATLEAST(2, 0, 0)
@ -37,7 +37,7 @@ bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext)
return false;
}
context->samples = context->obtainedSpec.samples;
context->psg = 0;
context->core = 0;
context->thread = 0;
if (threadContext) {
@ -59,9 +59,8 @@ bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread* threadContext)
return true;
}
void GBSDLDeinitAudio(struct GBSDLAudio* context) {
void mSDLDeinitAudio(struct mSDLAudio* context) {
UNUSED(context);
context->psg = 0;
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 1);
SDL_CloseAudioDevice(context->deviceId);
@ -72,7 +71,7 @@ void GBSDLDeinitAudio(struct GBSDLAudio* context) {
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
void GBSDLPauseAudio(struct GBSDLAudio* context) {
void mSDLPauseAudio(struct mSDLAudio* context) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 1);
#else
@ -81,7 +80,7 @@ void GBSDLPauseAudio(struct GBSDLAudio* context) {
#endif
}
void GBSDLResumeAudio(struct GBSDLAudio* context) {
void mSDLResumeAudio(struct mSDLAudio* context) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 0);
#else
@ -90,31 +89,39 @@ void GBSDLResumeAudio(struct GBSDLAudio* context) {
#endif
}
static void _GBSDLAudioCallback(void* context, Uint8* data, int len) {
struct GBSDLAudio* audioContext = context;
if (!context || (!audioContext->psg && !audioContext->thread)) {
static void _mSDLAudioCallback(void* context, Uint8* data, int len) {
struct mSDLAudio* audioContext = context;
if (!context || (!audioContext->core && !audioContext->thread)) {
memset(data, 0, len);
return;
}
struct GBAudio* psg = audioContext->psg;
if (!psg) {
psg = &audioContext->thread->gba->audio.psg;
blip_t* left = NULL;
blip_t* right = NULL;
int32_t clockRate;
if (audioContext->core) {
left = audioContext->core->getAudioChannel(audioContext->core, 0);
right = audioContext->core->getAudioChannel(audioContext->core, 1);
clockRate = audioContext->core->frequency(audioContext->core);
} else if (audioContext->thread) {
left = audioContext->thread->gba->audio.psg.left;
right = audioContext->thread->gba->audio.psg.right;
clockRate = GBA_ARM7TDMI_FREQUENCY;
}
double fauxClock = 1;
if (audioContext->thread) {
fauxClock = GBAAudioCalculateRatio(1, audioContext->thread->fpsTarget, 1);
mCoreSyncLockAudio(&audioContext->thread->sync);
}
blip_set_rates(psg->left, psg->clockRate, audioContext->obtainedSpec.freq * fauxClock);
blip_set_rates(psg->right, psg->clockRate, audioContext->obtainedSpec.freq * fauxClock);
blip_set_rates(left, clockRate, audioContext->obtainedSpec.freq * fauxClock);
blip_set_rates(right, clockRate, audioContext->obtainedSpec.freq * fauxClock);
len /= 2 * audioContext->obtainedSpec.channels;
int available = blip_samples_avail(psg->left);
int available = blip_samples_avail(left);
if (available > len) {
available = len;
}
blip_read_samples(psg->left, (short*) data, available, audioContext->obtainedSpec.channels == 2);
blip_read_samples(left, (short*) data, available, audioContext->obtainedSpec.channels == 2);
if (audioContext->obtainedSpec.channels == 2) {
blip_read_samples(psg->right, ((short*) data) + 1, available, 1);
blip_read_samples(right, ((short*) data) + 1, available, 1);
}
if (audioContext->sync) {

View File

@ -10,7 +10,7 @@
#include <SDL.h>
struct GBSDLAudio {
struct mSDLAudio {
// Input
size_t samples;
unsigned sampleRate;
@ -22,14 +22,14 @@ struct GBSDLAudio {
SDL_AudioDeviceID deviceId;
#endif
struct GBAudio* psg;
struct mCore* core;
struct GBAThread* thread;
struct mCoreSync* sync;
};
bool GBSDLInitAudio(struct GBSDLAudio* context, struct GBAThread*);
void GBSDLDeinitAudio(struct GBSDLAudio* context);
void GBSDLPauseAudio(struct GBSDLAudio* context);
void GBSDLResumeAudio(struct GBSDLAudio* context);
bool mSDLInitAudio(struct mSDLAudio* context, struct GBAThread*);
void mSDLDeinitAudio(struct mSDLAudio* context);
void mSDLPauseAudio(struct mSDLAudio* context);
void mSDLResumeAudio(struct mSDLAudio* context);
#endif