all repos — mgba @ adc57d0da7a09098cfc73a15cd034aa721474b68

mGBA Game Boy Advance Emulator

GB Audio: Miscellaneous fixes
Jeffrey Pfau jeffrey@endrift.com
Fri, 05 Feb 2016 20:44:25 -0800
commit

adc57d0da7a09098cfc73a15cd034aa721474b68

parent

c3c3bdc20c515892c9adf31336b928ac50bd5dc0

4 files changed, 240 insertions(+), 51 deletions(-)

jump to
M src/gb/audio.csrc/gb/audio.c

@@ -86,6 +86,7 @@ }

void GBAudioWriteNR11(struct GBAudio* audio, uint8_t value) { _writeDuty(&audio->ch1.envelope, value); + audio->ch1.control.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch1.envelope.length)) >> 8; } void GBAudioWriteNR12(struct GBAudio* audio, uint8_t value) {

@@ -103,7 +104,6 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) {

audio->ch1.control.frequency &= 0xFF; audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); audio->ch1.control.stop = GBAudioRegisterControlGetStop(value << 8); - audio->ch1.control.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch1.envelope.length)) >> 8; if (GBAudioRegisterControlIsRestart(value << 8)) { if (audio->ch1.time) { audio->ch1.nextSweep = audio->ch1.time * SWEEP_CYCLES;

@@ -132,6 +132,7 @@ }

void GBAudioWriteNR21(struct GBAudio* audio, uint8_t value) { _writeDuty(&audio->ch2.envelope, value); + audio->ch2.control.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch1.envelope.length)) >> 8; } void GBAudioWriteNR22(struct GBAudio* audio, uint8_t value) {

@@ -149,7 +150,6 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) {

audio->ch2.control.frequency &= 0xFF; audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); audio->ch2.control.stop = GBAudioRegisterControlGetStop(value << 8); - audio->ch2.control.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch2.envelope.length)) >> 8; if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh2 = 1; audio->ch2.envelope.currentVolume = audio->ch2.envelope.initialVolume;

@@ -180,6 +180,7 @@ }

void GBAudioWriteNR31(struct GBAudio* audio, uint8_t value) { audio->ch3.length = value; + audio->ch3.endTime = (DMG_LR35902_FREQUENCY * (256 - audio->ch3.length)) >> 8; } void GBAudioWriteNR32(struct GBAudio* audio, uint8_t value) {

@@ -195,7 +196,6 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) {

audio->ch3.rate &= 0xFF; audio->ch3.rate |= GBAudioRegisterControlGetRate(value << 8); audio->ch3.stop = GBAudioRegisterControlGetStop(value << 8); - audio->ch3.endTime = (DMG_LR35902_FREQUENCY * (256 - audio->ch3.length)) >> 8; if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh3 = audio->ch3.enable; }

@@ -210,6 +210,7 @@ }

void GBAudioWriteNR41(struct GBAudio* audio, uint8_t value) { _writeDuty(&audio->ch4.envelope, value); + audio->ch4.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch4.envelope.length)) >> 8; } void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) {

@@ -226,7 +227,6 @@ }

void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { audio->ch4.stop = GBAudioRegisterNoiseControlGetStop(value); - audio->ch4.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch4.envelope.length)) >> 8; if (GBAudioRegisterNoiseControlIsRestart(value)) { audio->playingCh4 = 1; audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume;

@@ -271,6 +271,55 @@ }

void GBAudioWriteNR52(struct GBAudio* audio, uint8_t value) { audio->enable = GBAudioEnableGetEnable(value); + if (!audio->enable) { + audio->playingCh1 = 0; + audio->playingCh2 = 0; + audio->playingCh3 = 0; + audio->playingCh4 = 0; + GBAudioWriteNR10(audio, 0); + GBAudioWriteNR11(audio, 0); + GBAudioWriteNR12(audio, 0); + GBAudioWriteNR13(audio, 0); + GBAudioWriteNR14(audio, 0); + GBAudioWriteNR21(audio, 0); + GBAudioWriteNR22(audio, 0); + GBAudioWriteNR23(audio, 0); + GBAudioWriteNR24(audio, 0); + GBAudioWriteNR30(audio, 0); + GBAudioWriteNR31(audio, 0); + GBAudioWriteNR32(audio, 0); + GBAudioWriteNR33(audio, 0); + GBAudioWriteNR34(audio, 0); + GBAudioWriteNR41(audio, 0); + GBAudioWriteNR42(audio, 0); + GBAudioWriteNR43(audio, 0); + GBAudioWriteNR44(audio, 0); + GBAudioWriteNR50(audio, 0); + GBAudioWriteNR51(audio, 0); + if (audio->p) { + audio->p->memory.io[REG_NR10] = 0; + audio->p->memory.io[REG_NR11] = 0; + audio->p->memory.io[REG_NR12] = 0; + audio->p->memory.io[REG_NR13] = 0; + audio->p->memory.io[REG_NR14] = 0; + audio->p->memory.io[REG_NR21] = 0; + audio->p->memory.io[REG_NR22] = 0; + audio->p->memory.io[REG_NR23] = 0; + audio->p->memory.io[REG_NR24] = 0; + audio->p->memory.io[REG_NR30] = 0; + audio->p->memory.io[REG_NR31] = 0; + audio->p->memory.io[REG_NR32] = 0; + audio->p->memory.io[REG_NR33] = 0; + audio->p->memory.io[REG_NR34] = 0; + audio->p->memory.io[REG_NR41] = 0; + audio->p->memory.io[REG_NR42] = 0; + audio->p->memory.io[REG_NR43] = 0; + audio->p->memory.io[REG_NR44] = 0; + audio->p->memory.io[REG_NR50] = 0; + audio->p->memory.io[REG_NR51] = 0; + audio->p->memory.io[REG_NR52] &= ~0x000F; + } + } } int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles) {

@@ -282,26 +331,28 @@ audio->eventDiff += cycles;

while (audio->nextEvent <= 0) { audio->nextEvent = INT_MAX; if (audio->enable) { - if (audio->playingCh1 && !audio->ch1.envelope.dead) { + if (audio->playingCh1) { audio->nextCh1 -= audio->eventDiff; - if (audio->ch1.envelope.nextStep != INT_MAX) { - audio->ch1.envelope.nextStep -= audio->eventDiff; - if (audio->ch1.envelope.nextStep <= 0) { - int8_t sample = audio->ch1.control.hi * 0x10 - 0x8; - _updateEnvelope(&audio->ch1.envelope); - if (audio->ch1.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch1.envelope.nextStep; + if (!audio->ch1.envelope.dead) { + if (audio->ch1.envelope.nextStep != INT_MAX) { + audio->ch1.envelope.nextStep -= audio->eventDiff; + if (audio->ch1.envelope.nextStep <= 0) { + int8_t sample = audio->ch1.control.hi * 0x10 - 0x8; + _updateEnvelope(&audio->ch1.envelope); + if (audio->ch1.envelope.nextStep < audio->nextEvent) { + audio->nextEvent = audio->ch1.envelope.nextStep; + } + audio->ch1.sample = sample * audio->ch1.envelope.currentVolume; } - audio->ch1.sample = sample * audio->ch1.envelope.currentVolume; } - } - if (audio->ch1.nextSweep != INT_MAX) { - audio->ch1.nextSweep -= audio->eventDiff; - if (audio->ch1.nextSweep <= 0) { - audio->playingCh1 = _updateSweep(&audio->ch1); - if (audio->ch1.nextSweep < audio->nextEvent) { - audio->nextEvent = audio->ch1.nextSweep; + if (audio->ch1.nextSweep != INT_MAX) { + audio->ch1.nextSweep -= audio->eventDiff; + if (audio->ch1.nextSweep <= 0) { + audio->playingCh1 = _updateSweep(&audio->ch1); + if (audio->ch1.nextSweep < audio->nextEvent) { + audio->nextEvent = audio->ch1.nextSweep; + } } } }

@@ -321,9 +372,9 @@ }

} } - if (audio->playingCh2 && !audio->ch2.envelope.dead) { + if (audio->playingCh2) { audio->nextCh2 -= audio->eventDiff; - if (audio->ch2.envelope.nextStep != INT_MAX) { + if (!audio->ch2.envelope.dead && audio->ch2.envelope.nextStep != INT_MAX) { audio->ch2.envelope.nextStep -= audio->eventDiff; if (audio->ch2.envelope.nextStep <= 0) { int8_t sample = audio->ch2.control.hi * 0x10 - 0x8;

@@ -367,9 +418,9 @@ }

} } - if (audio->playingCh4 && !audio->ch4.envelope.dead) { + if (audio->playingCh4) { audio->nextCh4 -= audio->eventDiff; - if (audio->ch4.envelope.nextStep != INT_MAX) { + if (!audio->ch4.envelope.dead && audio->ch4.envelope.nextStep != INT_MAX) { audio->ch4.envelope.nextStep -= audio->eventDiff; if (audio->ch4.envelope.nextStep <= 0) { int8_t sample = (audio->ch4.sample >> 31) * 0x8;
M src/gb/audio.hsrc/gb/audio.h

@@ -112,7 +112,7 @@ bool size;

bool bank; bool enable; - uint8_t length; + unsigned length; uint8_t volume; uint16_t rate;
M src/gb/io.csrc/gb/io.c

@@ -9,6 +9,32 @@ #include "gb/gb.h"

mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O"); +const static uint8_t _registerMask[0x50] = { + [REG_TAC] = 0xF8, + [REG_NR10] = 0x80, + [REG_NR11] = 0x3F, + [REG_NR12] = 0x00, + [REG_NR13] = 0xFF, + [REG_NR14] = 0xBF, + [REG_NR21] = 0x3F, + [REG_NR22] = 0x00, + [REG_NR23] = 0xFF, + [REG_NR24] = 0xBF, + [REG_NR30] = 0x7F, + [REG_NR31] = 0xFF, + [REG_NR32] = 0x9F, + [REG_NR33] = 0xFF, + [REG_NR34] = 0xBF, + [REG_NR41] = 0xFF, + [REG_NR42] = 0x00, + [REG_NR43] = 0x00, + [REG_NR44] = 0xBF, + [REG_NR50] = 0x00, + [REG_NR51] = 0x00, + [REG_NR52] = 0x70, + [REG_STAT] = 0x80, +}; + void GBIOInit(struct GB* gb) { memset(gb->memory.io, 0, sizeof(gb->memory.io)); }

@@ -56,67 +82,149 @@ case REG_DIV:

GBTimerDivReset(&gb->timer); return; case REG_NR10: - GBAudioWriteNR10(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR10(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR11: - GBAudioWriteNR11(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR11(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR12: - GBAudioWriteNR12(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR12(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR13: - GBAudioWriteNR13(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR13(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR14: - GBAudioWriteNR14(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR14(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR21: - GBAudioWriteNR21(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR21(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR22: - GBAudioWriteNR22(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR22(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR23: - GBAudioWriteNR23(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR23(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR24: - GBAudioWriteNR24(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR24(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR30: - GBAudioWriteNR30(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR30(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR31: - GBAudioWriteNR31(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR31(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR32: - GBAudioWriteNR32(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR32(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR33: - GBAudioWriteNR33(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR33(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR34: - GBAudioWriteNR34(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR34(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR41: - GBAudioWriteNR41(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR41(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR42: - GBAudioWriteNR42(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR42(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR43: - GBAudioWriteNR43(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR43(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR44: - GBAudioWriteNR44(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR44(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR50: - GBAudioWriteNR50(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR50(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR51: - GBAudioWriteNR51(&gb->audio, value); + if (gb->audio.enable) { + GBAudioWriteNR51(&gb->audio, value); + } else { + value = 0; + } break; case REG_NR52: GBAudioWriteNR52(&gb->audio, value); + value &= 0x80; + value |= gb->memory.io[REG_NR52] & 0x0F; break; case REG_WAVE_0: case REG_WAVE_1:

@@ -207,6 +315,39 @@ case REG_IF:

break; case REG_IE: return gb->memory.ie; + case REG_NR10: + case REG_NR11: + case REG_NR12: + case REG_NR14: + case REG_NR21: + case REG_NR22: + case REG_NR24: + case REG_NR30: + case REG_NR32: + case REG_NR34: + case REG_NR41: + case REG_NR42: + case REG_NR43: + case REG_NR44: + case REG_NR50: + case REG_NR51: + case REG_NR52: + case REG_WAVE_0: + case REG_WAVE_1: + case REG_WAVE_2: + case REG_WAVE_3: + case REG_WAVE_4: + case REG_WAVE_5: + case REG_WAVE_6: + case REG_WAVE_7: + case REG_WAVE_8: + case REG_WAVE_9: + case REG_WAVE_A: + case REG_WAVE_B: + case REG_WAVE_C: + case REG_WAVE_D: + case REG_WAVE_E: + case REG_WAVE_F: case REG_DIV: case REG_TIMA: case REG_TMA:

@@ -221,10 +362,7 @@ // Handled transparently by the registers

break; default: mLOG(GB_IO, STUB, "Reading from unknown register FF%02X", address); - if (address >= GB_SIZE_IO) { - return 0; - } - break; + return 0xFF; } - return gb->memory.io[address]; + return gb->memory.io[address] | _registerMask[address]; }
M src/gba/audio.csrc/gba/audio.c

@@ -201,7 +201,7 @@ }

void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) { audio->enable = GBAudioEnableGetEnable(value); - audio->psg.enable = audio->enable; + GBAudioWriteNR52(&audio->psg, value); } void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value) {