DS Audio: Initial implementation, only PCM
Vicki Pfau vi@endrift.com
Wed, 08 Mar 2017 00:12:18 -0800
7 files changed,
616 insertions(+),
4 deletions(-)
A
include/mgba/internal/ds/audio.h
@@ -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
M
include/mgba/internal/ds/ds.h
→
include/mgba/internal/ds/ds.h
@@ -14,6 +14,7 @@ #include <mgba/core/log.h>
#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 DSCommon ds7;
struct DSCommon ds9; struct DSMemory memory; struct DSVideo video; + struct DSAudio audio; struct DSGX gx; struct DSWifi wifi;
M
include/mgba/internal/ds/io.h
→
include/mgba/internal/ds/io.h
@@ -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@@ -120,6 +120,138 @@ DS7_REG_HALTCNT = 0x301,
DS7_REG_POWCNT2 = 0x304, 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,
A
src/ds/audio.c
@@ -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); +}
M
src/ds/core.c
→
src/ds/core.c
@@ -146,14 +146,25 @@ dscore->renderer.d.putPixels(&dscore->renderer.d, stride, buffer);
} 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) {
M
src/ds/ds.c
→
src/ds/ds.c
@@ -199,6 +199,9 @@
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 @@ CircleBufferDeinit(&ds->ds9.fifo);
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 @@ mTimingClear(&ds->ds7.timing);
CircleBufferInit(&ds->ds7.fifo, 64); DSMemoryReset(ds); DSDMAReset(&ds->ds7); + DSAudioReset(&ds->audio); DS7IOInit(ds); DSConfigureWRAM(&ds->memory, 3);
M
src/ds/io.c
→
src/ds/io.c
@@ -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 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#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 @@ break;
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 @@ break;
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);