mirror of https://github.com/mgba-emu/mgba.git
Core: Ability to enumerate and modify video and audio channels
This commit is contained in:
parent
9ced6724c1
commit
58c9bcf67a
1
CHANGES
1
CHANGES
|
@ -89,6 +89,7 @@ Misc:
|
|||
- Core: Restore sleep callback
|
||||
- Qt: Add .gb/.gbc files to the extension list in Info.plist
|
||||
- Feature: Make -l option explicit
|
||||
- Core: Ability to enumerate and modify video and audio channels
|
||||
|
||||
0.5.2: (2016-12-31)
|
||||
Bugfixes:
|
||||
|
|
|
@ -140,6 +140,11 @@ struct mCore {
|
|||
|
||||
size_t (*savedataClone)(struct mCore*, void** sram);
|
||||
bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback);
|
||||
|
||||
size_t (*listVideoLayers)(const struct mCore*, const struct mCoreChannelInfo**);
|
||||
size_t (*listAudioChannels)(const struct mCore*, const struct mCoreChannelInfo**);
|
||||
void (*enableVideoLayer)(struct mCore*, size_t id, bool enable);
|
||||
void (*enableAudioChannel)(struct mCore*, size_t id, bool enable);
|
||||
};
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
|
|
|
@ -105,6 +105,13 @@ struct mRumble {
|
|||
void (*setRumble)(struct mRumble*, int enable);
|
||||
};
|
||||
|
||||
struct mCoreChannelInfo {
|
||||
size_t id;
|
||||
const char* internalName;
|
||||
const char* visibleName;
|
||||
const char* visibleType;
|
||||
};
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,19 @@
|
|||
#include <mgba-util/patch.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
const static struct mCoreChannelInfo _GBVideoLayers[] = {
|
||||
{ 0, "bg", "Background", NULL },
|
||||
{ 1, "obj", "Objects", NULL },
|
||||
{ 2, "win", "Window", NULL },
|
||||
};
|
||||
|
||||
const static struct mCoreChannelInfo _GBAudioChannels[] = {
|
||||
{ 0, "ch0", "Channel 0", "Square/Sweep" },
|
||||
{ 1, "ch1", "Channel 1", "Square" },
|
||||
{ 2, "ch2", "Channel 2", "PCM" },
|
||||
{ 3, "ch3", "Channel 3", "Noise" },
|
||||
};
|
||||
|
||||
struct GBCore {
|
||||
struct mCore d;
|
||||
struct GBVideoSoftwareRenderer renderer;
|
||||
|
@ -579,6 +592,37 @@ static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBVideoLayers;
|
||||
return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers);
|
||||
}
|
||||
|
||||
static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBAudioChannels;
|
||||
return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels);
|
||||
}
|
||||
|
||||
static void _GBCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
|
||||
struct GB* gb = core->board;
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
|
||||
struct GB* gb = core->board;
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
gb->audio.forceDisableCh[id] = !enable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct mCore* GBCoreCreate(void) {
|
||||
struct GBCore* gbcore = malloc(sizeof(*gbcore));
|
||||
struct mCore* core = &gbcore->d;
|
||||
|
@ -647,5 +691,9 @@ struct mCore* GBCoreCreate(void) {
|
|||
core->cheatDevice = _GBCoreCheatDevice;
|
||||
core->savedataClone = _GBCoreSavedataClone;
|
||||
core->savedataRestore = _GBCoreSavedataRestore;
|
||||
core->listVideoLayers = _GBCoreListVideoLayers;
|
||||
core->listAudioChannels = _GBCoreListAudioChannels;
|
||||
core->enableVideoLayer = _GBCoreEnableVideoLayer;
|
||||
core->enableAudioChannel = _GBCoreEnableAudioChannel;
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,23 @@
|
|||
#include <mgba-util/patch.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
const static struct mCoreChannelInfo _GBAVideoLayers[] = {
|
||||
{ 0, "bg0", "Background 0", NULL },
|
||||
{ 1, "bg1", "Background 1", NULL },
|
||||
{ 2, "bg2", "Background 2", NULL },
|
||||
{ 3, "bg3", "Background 3", NULL },
|
||||
{ 4, "obj", "Objects", NULL },
|
||||
};
|
||||
|
||||
const static struct mCoreChannelInfo _GBAAudioChannels[] = {
|
||||
{ 0, "ch0", "PSG Channel 0", "Square/Sweep" },
|
||||
{ 1, "ch1", "PSG Channel 1", "Square" },
|
||||
{ 2, "ch2", "PSG Channel 2", "PCM" },
|
||||
{ 3, "ch3", "PSG Channel 3", "Noise" },
|
||||
{ 4, "chA", "FIFO Channel A", NULL },
|
||||
{ 5, "chB", "FIFO Channel B", NULL },
|
||||
};
|
||||
|
||||
struct GBACore {
|
||||
struct mCore d;
|
||||
struct GBAVideoSoftwareRenderer renderer;
|
||||
|
@ -581,6 +598,54 @@ static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
|||
return success;
|
||||
}
|
||||
|
||||
static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBAVideoLayers;
|
||||
return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers);
|
||||
}
|
||||
|
||||
static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBAAudioChannels;
|
||||
return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels);
|
||||
}
|
||||
|
||||
static void _GBACoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
|
||||
struct GBA* gba = core->board;
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
gba->video.renderer->disableBG[id] = !enable;
|
||||
break;
|
||||
case 4:
|
||||
gba->video.renderer->disableOBJ = !enable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
|
||||
struct GBA* gba = core->board;
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
gba->audio.psg.forceDisableCh[id] = !enable;
|
||||
break;
|
||||
case 4:
|
||||
gba->audio.forceDisableChA = !enable;
|
||||
case 5:
|
||||
gba->audio.forceDisableChB = !enable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct mCore* GBACoreCreate(void) {
|
||||
struct GBACore* gbacore = malloc(sizeof(*gbacore));
|
||||
struct mCore* core = &gbacore->d;
|
||||
|
@ -649,5 +714,9 @@ struct mCore* GBACoreCreate(void) {
|
|||
core->cheatDevice = _GBACoreCheatDevice;
|
||||
core->savedataClone = _GBACoreSavedataClone;
|
||||
core->savedataRestore = _GBACoreSavedataRestore;
|
||||
core->listVideoLayers = _GBACoreListVideoLayers;
|
||||
core->listAudioChannels = _GBACoreListAudioChannels;
|
||||
core->enableVideoLayer = _GBACoreEnableVideoLayer;
|
||||
core->enableAudioChannel = _GBACoreEnableAudioChannel;
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -57,8 +57,8 @@ GameController::GameController(QObject* parent)
|
|||
, m_turboForced(false)
|
||||
, m_turboSpeed(-1)
|
||||
, m_wasPaused(false)
|
||||
, m_audioChannels{ true, true, true, true, true, true }
|
||||
, m_videoLayers{ true, true, true, true, true }
|
||||
, m_audioChannels()
|
||||
, m_videoLayers()
|
||||
, m_autofire{}
|
||||
, m_autofireStatus{}
|
||||
, m_inputController(nullptr)
|
||||
|
@ -90,35 +90,17 @@ GameController::GameController(QObject* parent)
|
|||
context->core->setPeripheral(context->core, mPERIPH_ROTATION, controller->m_inputController->rotationSource());
|
||||
context->core->setPeripheral(context->core, mPERIPH_RUMBLE, controller->m_inputController->rumble());
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
GBA* gba = static_cast<GBA*>(context->core->board);
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
GB* gb = static_cast<GB*>(context->core->board);
|
||||
#endif
|
||||
for (size_t i = 0; i < controller->m_audioChannels.size(); ++i) {
|
||||
context->core->enableAudioChannel(context->core, i, controller->m_audioChannels[i]);
|
||||
}
|
||||
for (size_t i = 0; i < controller->m_videoLayers.size(); ++i) {
|
||||
context->core->enableVideoLayer(context->core, i, controller->m_videoLayers[i]);
|
||||
}
|
||||
|
||||
switch (context->core->platform(context->core)) {
|
||||
#ifdef M_CORE_GBA
|
||||
case PLATFORM_GBA:
|
||||
context->core->setPeripheral(context->core, mPERIPH_GBA_LUMINANCE, &controller->m_lux);
|
||||
gba->audio.psg.forceDisableCh[0] = !controller->m_audioChannels[0];
|
||||
gba->audio.psg.forceDisableCh[1] = !controller->m_audioChannels[1];
|
||||
gba->audio.psg.forceDisableCh[2] = !controller->m_audioChannels[2];
|
||||
gba->audio.psg.forceDisableCh[3] = !controller->m_audioChannels[3];
|
||||
gba->audio.forceDisableChA = !controller->m_audioChannels[4];
|
||||
gba->audio.forceDisableChB = !controller->m_audioChannels[5];
|
||||
gba->video.renderer->disableBG[0] = !controller->m_videoLayers[0];
|
||||
gba->video.renderer->disableBG[1] = !controller->m_videoLayers[1];
|
||||
gba->video.renderer->disableBG[2] = !controller->m_videoLayers[2];
|
||||
gba->video.renderer->disableBG[3] = !controller->m_videoLayers[3];
|
||||
gba->video.renderer->disableOBJ = !controller->m_videoLayers[4];
|
||||
break;
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
case PLATFORM_GB:
|
||||
gb->audio.forceDisableCh[0] = !controller->m_audioChannels[0];
|
||||
gb->audio.forceDisableCh[1] = !controller->m_audioChannels[1];
|
||||
gb->audio.forceDisableCh[2] = !controller->m_audioChannels[2];
|
||||
gb->audio.forceDisableCh[3] = !controller->m_audioChannels[3];
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -866,47 +848,13 @@ void GameController::setAudioChannelEnabled(int channel, bool enable) {
|
|||
if (channel > 5 || channel < 0) {
|
||||
return;
|
||||
}
|
||||
#ifdef M_CORE_GBA
|
||||
GBA* gba = static_cast<GBA*>(m_threadContext.core->board);
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
GB* gb = static_cast<GB*>(m_threadContext.core->board);
|
||||
#endif
|
||||
m_audioChannels.reserve(channel + 1);
|
||||
while (m_audioChannels.size() <= channel) {
|
||||
m_audioChannels.append(true);
|
||||
}
|
||||
m_audioChannels[channel] = enable;
|
||||
if (isLoaded()) {
|
||||
switch (channel) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
switch (m_threadContext.core->platform(m_threadContext.core)) {
|
||||
#ifdef M_CORE_GBA
|
||||
case PLATFORM_GBA:
|
||||
gba->audio.psg.forceDisableCh[channel] = !enable;
|
||||
break;
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
case PLATFORM_GB:
|
||||
gb->audio.forceDisableCh[channel] = !enable;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#ifdef M_CORE_GBA
|
||||
case 4:
|
||||
if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) {
|
||||
gba->audio.forceDisableChA = !enable;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) {
|
||||
gba->audio.forceDisableChB = !enable;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
m_threadContext.core->enableAudioChannel(m_threadContext.core, channel, enable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -925,24 +873,15 @@ void GameController::setVideoLayerEnabled(int layer, bool enable) {
|
|||
if (layer > 4 || layer < 0) {
|
||||
return;
|
||||
}
|
||||
m_videoLayers.reserve(layer + 1);
|
||||
while (m_videoLayers.size() <= layer) {
|
||||
m_videoLayers.append(true);
|
||||
}
|
||||
m_videoLayers[layer] = enable;
|
||||
#ifdef M_CORE_GBA
|
||||
if (isLoaded() && m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) {
|
||||
GBA* gba = static_cast<GBA*>(m_threadContext.core->board);
|
||||
switch (layer) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
gba->video.renderer->disableBG[layer] = !enable;
|
||||
break;
|
||||
case 4:
|
||||
gba->video.renderer->disableOBJ = !enable;
|
||||
break;
|
||||
if (isLoaded()) {
|
||||
m_threadContext.core->enableVideoLayer(m_threadContext.core, layer, enable);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GameController::setFPSTarget(float fps) {
|
||||
Interrupter interrupter(this);
|
||||
|
|
|
@ -222,8 +222,8 @@ private:
|
|||
|
||||
std::shared_ptr<mTileCache> m_tileCache;
|
||||
|
||||
bool m_audioChannels[6];
|
||||
bool m_videoLayers[5];
|
||||
QList<bool> m_audioChannels;
|
||||
QList<bool> m_videoLayers;
|
||||
|
||||
bool m_autofire[GBA_KEY_MAX];
|
||||
int m_autofireStatus[GBA_KEY_MAX];
|
||||
|
|
Loading…
Reference in New Issue