DS Audio: Initial implementation, only PCM

This commit is contained in:
Vicki Pfau 2017-03-08 00:12:18 -08:00
parent ebac3c65ea
commit 498aa541fc
7 changed files with 616 additions and 4 deletions

View File

@ -0,0 +1,102 @@
/* Copyright (c) 2013-2017 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 DS_AUDIO_H
#define DS_AUDIO_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba/core/log.h>
#include <mgba/core/timing.h>
mLOG_DECLARE_CATEGORY(DS_AUDIO);
DECL_BITFIELD(DSRegisterSOUNDxCNT, uint32_t);
DECL_BITS(DSRegisterSOUNDxCNT, VolumeMul, 0, 7);
DECL_BITS(DSRegisterSOUNDxCNT, VolumeDiv, 8, 2);
DECL_BIT(DSRegisterSOUNDxCNT, Hold, 15);
DECL_BITS(DSRegisterSOUNDxCNT, Panning, 16, 7);
DECL_BITS(DSRegisterSOUNDxCNT, Duty, 24, 3);
DECL_BITS(DSRegisterSOUNDxCNT, Repeat, 27, 2);
DECL_BITS(DSRegisterSOUNDxCNT, Format, 29, 2);
DECL_BIT(DSRegisterSOUNDxCNT, Busy, 31);
struct DSAudio;
struct DSAudioChannel {
struct DSAudio* p;
int index;
struct mTimingEvent updateEvent;
uint32_t source;
uint32_t loopPoint;
uint32_t length;
uint32_t offset;
unsigned volume;
unsigned divider;
int panning;
int format;
int repeat;
uint32_t period;
int16_t sample;
int adpcmOffset;
int16_t adpcmStartSample;
unsigned adpcmStartIndex;
int16_t adpcmSample;
unsigned adpcmIndex;
bool enable;
};
struct DS;
struct DSAudio {
struct DS* p;
struct blip_t* left;
struct blip_t* right;
struct DSAudioChannel ch[16];
int16_t lastLeft;
int16_t lastRight;
int clock;
int16_t sampleLeft;
int16_t sampleRight;
size_t samples;
unsigned sampleRate;
int32_t sampleInterval;
bool forceDisableCh[16];
int bias;
int masterVolume;
struct mTimingEvent sampleEvent;
};
void DSAudioInit(struct DSAudio*, size_t samples);
void DSAudioDeinit(struct DSAudio*);
void DSAudioReset(struct DSAudio*);
void DSAudioResizeBuffer(struct DSAudio* audio, size_t samples);
void DSAudioWriteSOUNDCNT_LO(struct DSAudio*, int chan, uint16_t value);
void DSAudioWriteSOUNDCNT_HI(struct DSAudio*, int chan, uint16_t value);
void DSAudioWriteSOUNDTMR(struct DSAudio*, int chan, uint16_t value);
void DSAudioWriteSOUNDPNT(struct DSAudio*, int chan, uint16_t value);
void DSAudioWriteSOUNDSAD(struct DSAudio*, int chan, uint32_t value);
void DSAudioWriteSOUNDLEN(struct DSAudio*, int chan, uint32_t value);
CXX_GUARD_END
#endif

View File

@ -14,6 +14,7 @@ CXX_GUARD_START
#include <mgba/core/timing.h>
#include <mgba-util/circle-buffer.h>
#include <mgba/internal/ds/audio.h>
#include <mgba/internal/ds/gx.h>
#include <mgba/internal/ds/memory.h>
#include <mgba/internal/ds/timer.h>
@ -85,6 +86,7 @@ struct DS {
struct DSCommon ds9;
struct DSMemory memory;
struct DSVideo video;
struct DSAudio audio;
struct DSGX gx;
struct DSWifi wifi;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
/* Copyright (c) 2013-2017 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
@ -121,6 +121,138 @@ enum DS7IORegisters {
DS7_REG_BIOSPROT_LO = 0x308,
DS7_REG_BIOSPROT_HI = 0x30A,
// Audio
DS7_REG_SOUND0CNT_LO = 0x400,
DS7_REG_SOUND0CNT_HI = 0x402,
DS7_REG_SOUND0SAD_LO = 0x404,
DS7_REG_SOUND0SAD_HI = 0x406,
DS7_REG_SOUND0TMR = 0x408,
DS7_REG_SOUND0PNT = 0x40A,
DS7_REG_SOUND0LEN_LO = 0x40C,
DS7_REG_SOUND0LEN_HI = 0x40E,
DS7_REG_SOUND1CNT_LO = 0x410,
DS7_REG_SOUND1CNT_HI = 0x412,
DS7_REG_SOUND1SAD_LO = 0x414,
DS7_REG_SOUND1SAD_HI = 0x416,
DS7_REG_SOUND1TMR = 0x418,
DS7_REG_SOUND1PNT = 0x41A,
DS7_REG_SOUND1LEN_LO = 0x41C,
DS7_REG_SOUND1LEN_HI = 0x41E,
DS7_REG_SOUND2CNT_LO = 0x420,
DS7_REG_SOUND2CNT_HI = 0x422,
DS7_REG_SOUND2SAD_LO = 0x424,
DS7_REG_SOUND2SAD_HI = 0x426,
DS7_REG_SOUND2TMR = 0x428,
DS7_REG_SOUND2PNT = 0x42A,
DS7_REG_SOUND2LEN_LO = 0x42C,
DS7_REG_SOUND2LEN_HI = 0x42E,
DS7_REG_SOUND3CNT_LO = 0x430,
DS7_REG_SOUND3CNT_HI = 0x432,
DS7_REG_SOUND3SAD_LO = 0x434,
DS7_REG_SOUND3SAD_HI = 0x436,
DS7_REG_SOUND3TMR = 0x438,
DS7_REG_SOUND3PNT = 0x43A,
DS7_REG_SOUND3LEN_LO = 0x43C,
DS7_REG_SOUND3LEN_HI = 0x43E,
DS7_REG_SOUND4CNT_LO = 0x440,
DS7_REG_SOUND4CNT_HI = 0x442,
DS7_REG_SOUND4SAD_LO = 0x444,
DS7_REG_SOUND4SAD_HI = 0x446,
DS7_REG_SOUND4TMR = 0x448,
DS7_REG_SOUND4PNT = 0x44A,
DS7_REG_SOUND4LEN_LO = 0x44C,
DS7_REG_SOUND4LEN_HI = 0x44E,
DS7_REG_SOUND5CNT_LO = 0x450,
DS7_REG_SOUND5CNT_HI = 0x452,
DS7_REG_SOUND5SAD_LO = 0x454,
DS7_REG_SOUND5SAD_HI = 0x456,
DS7_REG_SOUND5TMR = 0x458,
DS7_REG_SOUND5PNT = 0x45A,
DS7_REG_SOUND5LEN_LO = 0x45C,
DS7_REG_SOUND5LEN_HI = 0x45E,
DS7_REG_SOUND6CNT_LO = 0x460,
DS7_REG_SOUND6CNT_HI = 0x462,
DS7_REG_SOUND6SAD_LO = 0x464,
DS7_REG_SOUND6SAD_HI = 0x466,
DS7_REG_SOUND6TMR = 0x468,
DS7_REG_SOUND6PNT = 0x46A,
DS7_REG_SOUND6LEN_LO = 0x46C,
DS7_REG_SOUND6LEN_HI = 0x46E,
DS7_REG_SOUND7CNT_LO = 0x470,
DS7_REG_SOUND7CNT_HI = 0x472,
DS7_REG_SOUND7SAD_LO = 0x474,
DS7_REG_SOUND7SAD_HI = 0x476,
DS7_REG_SOUND7TMR = 0x478,
DS7_REG_SOUND7PNT = 0x47A,
DS7_REG_SOUND7LEN_LO = 0x47C,
DS7_REG_SOUND7LEN_HI = 0x47E,
DS7_REG_SOUND8CNT_LO = 0x480,
DS7_REG_SOUND8CNT_HI = 0x482,
DS7_REG_SOUND8SAD_LO = 0x484,
DS7_REG_SOUND8SAD_HI = 0x486,
DS7_REG_SOUND8TMR = 0x488,
DS7_REG_SOUND8PNT = 0x48A,
DS7_REG_SOUND8LEN_LO = 0x48C,
DS7_REG_SOUND8LEN_HI = 0x48E,
DS7_REG_SOUND9CNT_LO = 0x490,
DS7_REG_SOUND9CNT_HI = 0x492,
DS7_REG_SOUND9SAD_LO = 0x494,
DS7_REG_SOUND9SAD_HI = 0x496,
DS7_REG_SOUND9TMR = 0x498,
DS7_REG_SOUND9PNT = 0x49A,
DS7_REG_SOUND9LEN_LO = 0x49C,
DS7_REG_SOUND9LEN_HI = 0x49E,
DS7_REG_SOUNDACNT_LO = 0x4A0,
DS7_REG_SOUNDACNT_HI = 0x4A2,
DS7_REG_SOUNDASAD_LO = 0x4A4,
DS7_REG_SOUNDASAD_HI = 0x4A6,
DS7_REG_SOUNDATMR = 0x4A8,
DS7_REG_SOUNDAPNT = 0x4AA,
DS7_REG_SOUNDALEN_LO = 0x4AC,
DS7_REG_SOUNDALEN_HI = 0x4AE,
DS7_REG_SOUNDBCNT_LO = 0x4B0,
DS7_REG_SOUNDBCNT_HI = 0x4B2,
DS7_REG_SOUNDBSAD_LO = 0x4B4,
DS7_REG_SOUNDBSAD_HI = 0x4B6,
DS7_REG_SOUNDBTMR = 0x4B8,
DS7_REG_SOUNDBPNT = 0x4BA,
DS7_REG_SOUNDBLEN_LO = 0x4BC,
DS7_REG_SOUNDBLEN_HI = 0x4BE,
DS7_REG_SOUNDCCNT_LO = 0x4C0,
DS7_REG_SOUNDCCNT_HI = 0x4C2,
DS7_REG_SOUNDCSAD_LO = 0x4C4,
DS7_REG_SOUNDCSAD_HI = 0x4C6,
DS7_REG_SOUNDCTMR = 0x4C8,
DS7_REG_SOUNDCPNT = 0x4CA,
DS7_REG_SOUNDCLEN_LO = 0x4CC,
DS7_REG_SOUNDCLEN_HI = 0x4CE,
DS7_REG_SOUNDDCNT_LO = 0x4D0,
DS7_REG_SOUNDDCNT_HI = 0x4D2,
DS7_REG_SOUNDDSAD_LO = 0x4D4,
DS7_REG_SOUNDDSAD_HI = 0x4D6,
DS7_REG_SOUNDDTMR = 0x4D8,
DS7_REG_SOUNDDPNT = 0x4DA,
DS7_REG_SOUNDDLEN_LO = 0x4DC,
DS7_REG_SOUNDDLEN_HI = 0x4DE,
DS7_REG_SOUNDECNT_LO = 0x4E0,
DS7_REG_SOUNDECNT_HI = 0x4E2,
DS7_REG_SOUNDESAD_LO = 0x4E4,
DS7_REG_SOUNDESAD_HI = 0x4E6,
DS7_REG_SOUNDETMR = 0x4E8,
DS7_REG_SOUNDEPNT = 0x4EA,
DS7_REG_SOUNDELEN_LO = 0x4EC,
DS7_REG_SOUNDELEN_HI = 0x4EE,
DS7_REG_SOUNDFCNT_LO = 0x4F0,
DS7_REG_SOUNDFCNT_HI = 0x4F2,
DS7_REG_SOUNDFSAD_LO = 0x4F4,
DS7_REG_SOUNDFSAD_HI = 0x4F6,
DS7_REG_SOUNDFTMR = 0x4F8,
DS7_REG_SOUNDFPNT = 0x4FA,
DS7_REG_SOUNDFLEN_LO = 0x4FC,
DS7_REG_SOUNDFLEN_HI = 0x4FE,
DS7_REG_SOUNDCNT = 0x500,
DS7_REG_SOUNDBIAS = 0x504,
DS7_REG_MAX = 0x51E,
DS7_IO_BASE_WIFI = 0x800000,

245
src/ds/audio.c Normal file
View File

@ -0,0 +1,245 @@
/* Copyright (c) 2013-2017 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 <mgba/internal/ds/audio.h>
#include <mgba/core/blip_buf.h>
#include <mgba/core/sync.h>
#include <mgba/internal/ds/ds.h>
mLOG_DEFINE_CATEGORY(DS_AUDIO, "DS Audio", "ds.audio");
static const unsigned BLIP_BUFFER_SIZE = 0x4000;
static const int CLOCKS_PER_FRAME = 0x4000;
const int DS_AUDIO_VOLUME_MAX = 0x100;
static void _updateChannel(struct mTiming* timing, void* user, uint32_t cyclesLate);
static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate);
static void _updateMixer(struct DSAudio*);
void DSAudioInit(struct DSAudio* audio, size_t samples) {
audio->samples = samples;
audio->left = blip_new(BLIP_BUFFER_SIZE);
audio->right = blip_new(BLIP_BUFFER_SIZE);
audio->ch[0].updateEvent.name = "DS Audio Channel 0";
audio->ch[1].updateEvent.name = "DS Audio Channel 1";
audio->ch[2].updateEvent.name = "DS Audio Channel 2";
audio->ch[3].updateEvent.name = "DS Audio Channel 3";
audio->ch[4].updateEvent.name = "DS Audio Channel 4";
audio->ch[5].updateEvent.name = "DS Audio Channel 5";
audio->ch[6].updateEvent.name = "DS Audio Channel 6";
audio->ch[7].updateEvent.name = "DS Audio Channel 7";
audio->ch[8].updateEvent.name = "DS Audio Channel 8";
audio->ch[9].updateEvent.name = "DS Audio Channel 9";
audio->ch[10].updateEvent.name = "DS Audio Channel 10";
audio->ch[11].updateEvent.name = "DS Audio Channel 11";
audio->ch[12].updateEvent.name = "DS Audio Channel 12";
audio->ch[13].updateEvent.name = "DS Audio Channel 13";
audio->ch[14].updateEvent.name = "DS Audio Channel 14";
audio->ch[15].updateEvent.name = "DS Audio Channel 15";
int ch;
for (ch = 0; ch < 16; ++ch) {
audio->ch[ch].index = ch;
audio->ch[ch].updateEvent.priority = 0x10 | ch;
audio->ch[ch].updateEvent.context = &audio->ch[ch];
audio->ch[ch].updateEvent.callback = _updateChannel;
audio->ch[ch].p = audio;
audio->forceDisableCh[ch] = false;
}
audio->masterVolume = DS_AUDIO_VOLUME_MAX;
audio->sampleEvent.name = "DS Audio Sample";
audio->sampleEvent.context = audio;
audio->sampleEvent.callback = _sample;
audio->sampleEvent.priority = 0x110;
blip_set_rates(audio->left, DS_ARM7TDMI_FREQUENCY, 96000);
blip_set_rates(audio->right, DS_ARM7TDMI_FREQUENCY, 96000);
}
void DSAudioDeinit(struct DSAudio* audio) {
blip_delete(audio->left);
blip_delete(audio->right);
}
void DSAudioReset(struct DSAudio* audio) {
mTimingDeschedule(&audio->p->ds7.timing, &audio->sampleEvent);
mTimingSchedule(&audio->p->ds7.timing, &audio->sampleEvent, 0);
audio->sampleRate = 0x8000;
audio->sampleInterval = DS_ARM7TDMI_FREQUENCY / audio->sampleRate;
int ch;
for (ch = 0; ch < 16; ++ch) {
audio->ch[ch].source = 0;
audio->ch[ch].loopPoint = 0;
audio->ch[ch].length = 0;
audio->ch[ch].offset = 0;
audio->ch[ch].sample = 0;
}
blip_clear(audio->left);
blip_clear(audio->right);
audio->clock = 0;
audio->bias = 0x200;
}
void DSAudioResizeBuffer(struct DSAudio* audio, size_t samples) {
// TODO: Share between other cores
mCoreSyncLockAudio(audio->p->sync);
audio->samples = samples;
blip_clear(audio->left);
blip_clear(audio->right);
audio->clock = 0;
mCoreSyncConsumeAudio(audio->p->sync);
}
void DSAudioWriteSOUNDCNT_LO(struct DSAudio* audio, int chan, uint16_t value) {
audio->ch[chan].volume = DSRegisterSOUNDxCNTGetVolumeMul(value);
audio->ch[chan].divider = DSRegisterSOUNDxCNTGetVolumeDiv(value);
if (audio->ch[chan].divider == 3) {
++audio->ch[chan].divider;
}
}
void DSAudioWriteSOUNDCNT_HI(struct DSAudio* audio, int chan, uint16_t value) {
DSRegisterSOUNDxCNT reg = value << 16;
struct DSAudioChannel* ch = &audio->ch[chan];
ch->panning = DSRegisterSOUNDxCNTGetPanning(reg);
ch->repeat = DSRegisterSOUNDxCNTGetRepeat(reg);
ch->format = DSRegisterSOUNDxCNTGetFormat(reg);
if (ch->format >= 2) {
mLOG(DS_AUDIO, STUB, "Unimplemented audio format %i", ch->format);
}
if (ch->enable && !DSRegisterSOUNDxCNTIsBusy(reg)) {
mTimingDeschedule(&audio->p->ds7.timing, &ch->updateEvent);
} else if (!ch->enable && DSRegisterSOUNDxCNTIsBusy(reg)) {
ch->offset = 0;
mTimingDeschedule(&audio->p->ds7.timing, &ch->updateEvent);
mTimingSchedule(&audio->p->ds7.timing, &ch->updateEvent, 0);
}
ch->enable = DSRegisterSOUNDxCNTIsBusy(reg);
}
void DSAudioWriteSOUNDTMR(struct DSAudio* audio, int chan, uint16_t value) {
audio->ch[chan].period = (0x10000 - value) << 1;
}
void DSAudioWriteSOUNDPNT(struct DSAudio* audio, int chan, uint16_t value) {
audio->ch[chan].loopPoint = value << 2;
}
void DSAudioWriteSOUNDSAD(struct DSAudio* audio, int chan, uint32_t value) {
audio->ch[chan].source = value;
}
void DSAudioWriteSOUNDLEN(struct DSAudio* audio, int chan, uint32_t value) {
audio->ch[chan].length = value << 2;
}
static void _updateMixer(struct DSAudio* audio) {
int32_t sampleLeft = 0;
int32_t sampleRight = 0;
int ch;
for (ch = 0; ch < 16; ++ch) {
if (!audio->ch[ch].enable) {
continue;
}
int32_t sample = audio->ch[ch].sample << 4;
sample >>= audio->ch[ch].divider;
sample *= audio->ch[ch].volume;
sample >>= 2;
int32_t left = sample * (0x7F - audio->ch[ch].panning);
int32_t right = sample * audio->ch[ch].panning;
sampleLeft += left >>= 16;
sampleRight += right >>= 16;
}
audio->sampleLeft = sampleLeft >> 6;
audio->sampleRight = sampleRight >> 6;
}
static void _updateChannel(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct DSAudioChannel* ch = user;
struct ARMCore* cpu = ch->p->p->ds7.cpu;
switch (ch->format) {
case 0:
ch->sample = cpu->memory.load8(cpu, ch->offset + ch->source, NULL) << 8;
++ch->offset;
break;
case 1:
ch->sample = cpu->memory.load16(cpu, ch->offset + ch->source, NULL);
ch->offset += 2;
break;
case 2:
// TODO
ch->enable = false;
break;
}
_updateMixer(ch->p);
switch (ch->repeat) {
case 1:
if (ch->offset >= ch->length) {
ch->offset = ch->loopPoint;
}
break;
case 2:
if (ch->offset >= ch->length) {
ch->enable = false;
ch->p->p->memory.io7[(DS7_REG_SOUND0CNT_HI + (ch->index << 4)) >> 1] &= 0x7FFF;
}
break;
}
if (ch->enable) {
mTimingSchedule(timing, &ch->updateEvent, ch->period - cyclesLate);
}
}
static int _applyBias(struct DSAudio* audio, int sample) {
sample += audio->bias;
if (sample >= 0x400) {
sample = 0x3FF;
} else if (sample < 0) {
sample = 0;
}
return ((sample - audio->bias) * audio->masterVolume) >> 3;
}
static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct DSAudio* audio = user;
int16_t sampleLeft = _applyBias(audio, audio->sampleLeft);
int16_t sampleRight = _applyBias(audio, audio->sampleRight);
mCoreSyncLockAudio(audio->p->sync);
unsigned produced;
if ((size_t) blip_samples_avail(audio->left) < audio->samples) {
blip_add_delta(audio->left, audio->clock, sampleLeft - audio->lastLeft);
blip_add_delta(audio->right, audio->clock, sampleRight - audio->lastRight);
audio->lastLeft = sampleLeft;
audio->lastRight = sampleRight;
audio->clock += audio->sampleInterval;
if (audio->clock >= CLOCKS_PER_FRAME) {
blip_end_frame(audio->left, audio->clock);
blip_end_frame(audio->right, audio->clock);
audio->clock -= CLOCKS_PER_FRAME;
}
}
produced = blip_samples_avail(audio->left);
if (audio->p->stream && audio->p->stream->postAudioFrame) {
audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight);
}
bool wait = produced >= audio->samples;
mCoreSyncProduceAudio(audio->p->sync, wait);
if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) {
audio->p->stream->postAudioBuffer(audio->p->stream, audio->left, audio->right);
}
mTimingSchedule(timing, &audio->sampleEvent, audio->sampleInterval - cyclesLate);
}

View File

@ -146,14 +146,25 @@ static void _DSCorePutPixels(struct mCore* core, const void* buffer, size_t stri
}
static struct blip_t* _DSCoreGetAudioChannel(struct mCore* core, int ch) {
return NULL;
struct DS* ds = core->board;
switch (ch) {
case 0:
return ds->audio.left;
case 1:
return ds->audio.right;
default:
return NULL;
}
}
static void _DSCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
struct DS* ds = core->board;
DSAudioResizeBuffer(&ds->audio, samples);
}
static size_t _DSCoreGetAudioBufferSize(struct mCore* core) {
return 2048;
struct DS* ds = core->board;
return ds->audio.samples;
}
static void _DSCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {

View File

@ -199,6 +199,9 @@ static void DSInit(void* cpu, struct mCPUComponent* component) {
DSGXInit(&ds->gx);
ds->gx.p = ds;
DSAudioInit(&ds->audio, 2048);
ds->audio.p = ds;
ds->ds7.springIRQ = 0;
ds->ds9.springIRQ = 0;
DSTimerInit(ds);
@ -240,6 +243,7 @@ void DSDestroy(struct DS* ds) {
DSUnloadROM(ds);
DSMemoryDeinit(ds);
DSGXDeinit(&ds->gx);
DSAudioDeinit(&ds->audio);
mTimingDeinit(&ds->ds7.timing);
mTimingDeinit(&ds->ds9.timing);
mCoreCallbacksListDeinit(&ds->coreCallbacks);
@ -286,6 +290,7 @@ void DS7Reset(struct ARMCore* cpu) {
CircleBufferInit(&ds->ds7.fifo, 64);
DSMemoryReset(ds);
DSDMAReset(&ds->ds7);
DSAudioReset(&ds->audio);
DS7IOInit(ds);
DSConfigureWRAM(&ds->memory, 3);

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
/* Copyright (c) 2013-2017 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
@ -6,6 +6,7 @@
#include <mgba/internal/ds/io.h>
#include <mgba/core/interface.h>
#include <mgba/internal/ds/audio.h>
#include <mgba/internal/ds/ds.h>
#include <mgba/internal/ds/gx.h>
#include <mgba/internal/ds/ipc.h>
@ -272,6 +273,80 @@ void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
case DS7_REG_SPIDATA:
DSSPIWrite(ds, value);
break;
case DS7_REG_SOUND0CNT_LO:
case DS7_REG_SOUND1CNT_LO:
case DS7_REG_SOUND2CNT_LO:
case DS7_REG_SOUND3CNT_LO:
case DS7_REG_SOUND4CNT_LO:
case DS7_REG_SOUND5CNT_LO:
case DS7_REG_SOUND6CNT_LO:
case DS7_REG_SOUND7CNT_LO:
case DS7_REG_SOUND8CNT_LO:
case DS7_REG_SOUND9CNT_LO:
case DS7_REG_SOUNDACNT_LO:
case DS7_REG_SOUNDBCNT_LO:
case DS7_REG_SOUNDCCNT_LO:
case DS7_REG_SOUNDDCNT_LO:
case DS7_REG_SOUNDECNT_LO:
case DS7_REG_SOUNDFCNT_LO:
value &= 0x837F;
DSAudioWriteSOUNDCNT_LO(&ds->audio, (address - DS7_REG_SOUND0CNT_LO) >> 4, value);
break;
case DS7_REG_SOUND0CNT_HI:
case DS7_REG_SOUND1CNT_HI:
case DS7_REG_SOUND2CNT_HI:
case DS7_REG_SOUND3CNT_HI:
case DS7_REG_SOUND4CNT_HI:
case DS7_REG_SOUND5CNT_HI:
case DS7_REG_SOUND6CNT_HI:
case DS7_REG_SOUND7CNT_HI:
case DS7_REG_SOUND8CNT_HI:
case DS7_REG_SOUND9CNT_HI:
case DS7_REG_SOUNDACNT_HI:
case DS7_REG_SOUNDBCNT_HI:
case DS7_REG_SOUNDCCNT_HI:
case DS7_REG_SOUNDDCNT_HI:
case DS7_REG_SOUNDECNT_HI:
case DS7_REG_SOUNDFCNT_HI:
value &= 0xFF7F;
DSAudioWriteSOUNDCNT_HI(&ds->audio, (address - DS7_REG_SOUND0CNT_HI) >> 4, value);
break;
case DS7_REG_SOUND0TMR:
case DS7_REG_SOUND1TMR:
case DS7_REG_SOUND2TMR:
case DS7_REG_SOUND3TMR:
case DS7_REG_SOUND4TMR:
case DS7_REG_SOUND5TMR:
case DS7_REG_SOUND6TMR:
case DS7_REG_SOUND7TMR:
case DS7_REG_SOUND8TMR:
case DS7_REG_SOUND9TMR:
case DS7_REG_SOUNDATMR:
case DS7_REG_SOUNDBTMR:
case DS7_REG_SOUNDCTMR:
case DS7_REG_SOUNDDTMR:
case DS7_REG_SOUNDETMR:
case DS7_REG_SOUNDFTMR:
DSAudioWriteSOUNDTMR(&ds->audio, (address - DS7_REG_SOUND0TMR) >> 4, value);
break;
case DS7_REG_SOUND0PNT:
case DS7_REG_SOUND1PNT:
case DS7_REG_SOUND2PNT:
case DS7_REG_SOUND3PNT:
case DS7_REG_SOUND4PNT:
case DS7_REG_SOUND5PNT:
case DS7_REG_SOUND6PNT:
case DS7_REG_SOUND7PNT:
case DS7_REG_SOUND8PNT:
case DS7_REG_SOUND9PNT:
case DS7_REG_SOUNDAPNT:
case DS7_REG_SOUNDBPNT:
case DS7_REG_SOUNDCPNT:
case DS7_REG_SOUNDDPNT:
case DS7_REG_SOUNDEPNT:
case DS7_REG_SOUNDFPNT:
DSAudioWriteSOUNDPNT(&ds->audio, (address - DS7_REG_SOUND0PNT) >> 4, value);
break;
default:
{
uint32_t v2 = DSIOWrite(&ds->ds7, address, value);
@ -337,6 +412,46 @@ void DS7IOWrite32(struct DS* ds, uint32_t address, uint32_t value) {
case DS_REG_DMA3CNT_LO:
DS7DMAWriteCNT(&ds->ds7, 3, value);
break;
case DS7_REG_SOUND0SAD_LO:
case DS7_REG_SOUND1SAD_LO:
case DS7_REG_SOUND2SAD_LO:
case DS7_REG_SOUND3SAD_LO:
case DS7_REG_SOUND4SAD_LO:
case DS7_REG_SOUND5SAD_LO:
case DS7_REG_SOUND6SAD_LO:
case DS7_REG_SOUND7SAD_LO:
case DS7_REG_SOUND8SAD_LO:
case DS7_REG_SOUND9SAD_LO:
case DS7_REG_SOUNDASAD_LO:
case DS7_REG_SOUNDBSAD_LO:
case DS7_REG_SOUNDCSAD_LO:
case DS7_REG_SOUNDDSAD_LO:
case DS7_REG_SOUNDESAD_LO:
case DS7_REG_SOUNDFSAD_LO:
DSAudioWriteSOUNDSAD(&ds->audio, (address - DS7_REG_SOUND0SAD_LO) >> 4, value);
break;
case DS7_REG_SOUND0LEN_LO:
case DS7_REG_SOUND1LEN_LO:
case DS7_REG_SOUND2LEN_LO:
case DS7_REG_SOUND3LEN_LO:
case DS7_REG_SOUND4LEN_LO:
case DS7_REG_SOUND5LEN_LO:
case DS7_REG_SOUND6LEN_LO:
case DS7_REG_SOUND7LEN_LO:
case DS7_REG_SOUND8LEN_LO:
case DS7_REG_SOUND9LEN_LO:
case DS7_REG_SOUNDALEN_LO:
case DS7_REG_SOUNDBLEN_LO:
case DS7_REG_SOUNDCLEN_LO:
case DS7_REG_SOUNDDLEN_LO:
case DS7_REG_SOUNDELEN_LO:
case DS7_REG_SOUNDFLEN_LO:
value &= 0x3FFFFF;
DSAudioWriteSOUNDLEN(&ds->audio, (address - DS7_REG_SOUND0LEN_LO) >> 4, value);
break;
default:
DS7IOWrite(ds, address, value & 0xFFFF);
DS7IOWrite(ds, address | 2, value >> 16);