GBA Audio: Redo channel 4 batching for GBA only

This commit is contained in:
Vicki Pfau 2020-01-01 16:59:57 -08:00
parent f5f855a105
commit ad870aa26b
5 changed files with 35 additions and 10 deletions

View File

@ -110,6 +110,7 @@ Other fixes:
- Qt: Fix inability to clear default keybindings
Misc:
- GB Memory: Support manual SRAM editing (fixes mgba.io/i/1580)
- GBA Audio: Redo channel 4 batching for GBA only
- GBA I/O: Stop logging several harmless invalid register reads
- Debugger: Separate aliases from main commands
- Debugger: Print break-/watchpoint ID when breaking in CLI

View File

@ -139,6 +139,7 @@ struct GBAudioNoiseChannel {
uint32_t lfsr;
int nSamples;
int samples;
uint32_t lastEvent;
int8_t sample;
};

View File

@ -79,7 +79,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | bits 0 - 2: Remaining length
* | bits 3 - 5: Next step
* | bits 6 - 31: Reserved
* | 0x00098 - 0x0009F: Reserved
* | 0x0009C - 0x0009F: Last event
* | 0x000A0 - 0x000A3: Next event
* 0x000A4 - 0x000B7: Audio miscellaneous state
* | TODO: Fix this, they're in big-endian order, but field is little-endian
@ -224,7 +224,7 @@ struct GBSerializedPSGState {
struct {
int32_t lfsr;
GBSerializedAudioEnvelope envelope;
int32_t reserved;
int32_t lastEvent;
uint32_t nextEvent;
} ch4;
};

View File

@ -61,7 +61,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | bits 0 - 2: Remaining length
* | bits 3 - 5: Next step
* | bits 6 - 31: Reserved
* | 0x00184 - 0x00187: Reserved
* | 0x00184 - 0x00187: Last event
* | 0x00188 - 0x0018B: Next event
* 0x0018C - 0x001AB: Audio FIFO 1
* 0x001AC - 0x001CB: Audio FIFO 2

View File

@ -359,6 +359,7 @@ void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) {
}
void GBAudioWriteNR43(struct GBAudio* audio, uint8_t value) {
// TODO: Reschedule event
audio->ch4.ratio = GBAudioRegisterNoiseFeedbackGetRatio(value);
audio->ch4.frequency = GBAudioRegisterNoiseFeedbackGetFrequency(value);
audio->ch4.power = GBAudioRegisterNoiseFeedbackGetPower(value);
@ -933,14 +934,30 @@ static void _updateChannel4(struct mTiming* timing, void* user, uint32_t cyclesL
cycles <<= ch->frequency;
cycles *= 8 * audio->timingFactor;
int lsb = ch->lfsr & 1;
ch->sample = lsb * ch->envelope.currentVolume;
++ch->nSamples;
ch->samples += ch->sample;
ch->lfsr >>= 1;
ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8);
uint32_t last = 0;
uint32_t now = cycles;
uint32_t next = cycles - cyclesLate;
mTimingSchedule(timing, &audio->ch4Event, cycles - cyclesLate);
if (audio->style == GB_AUDIO_GBA) {
last = ch->lastEvent;
now = mTimingCurrentTime(timing) - cyclesLate;
ch->lastEvent = now;
now -= last;
last = 0;
// TODO: Make batching work when descheduled
next = audio->sampleInterval;
}
for (; last < now; last += cycles) {
int lsb = ch->lfsr & 1;
ch->sample = lsb * ch->envelope.currentVolume;
++ch->nSamples;
ch->samples += ch->sample;
ch->lfsr >>= 1;
ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8);
}
mTimingSchedule(timing, &audio->ch4Event, next);
}
void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut) {
@ -984,6 +1001,7 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat
ch4Flags = GBSerializedAudioEnvelopeSetLength(ch4Flags, audio->ch4.length);
ch4Flags = GBSerializedAudioEnvelopeSetNextStep(ch4Flags, audio->ch4.envelope.nextStep);
STORE_32LE(ch4Flags, 0, &state->ch4.envelope);
STORE_32LE(audio->ch4.lastEvent, 0, &state->ch4.lastEvent);
STORE_32LE(audio->ch4Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch4.nextEvent);
STORE_32LE(flags, 0, flagsOut);
@ -1055,8 +1073,13 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
audio->ch4.length = GBSerializedAudioEnvelopeGetLength(ch4Flags);
audio->ch4.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch4Flags);
LOAD_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr);
LOAD_32LE(audio->ch4.lastEvent, 0, &state->ch4.lastEvent);
LOAD_32LE(when, 0, &state->ch4.nextEvent);
if (audio->ch4.envelope.dead < 2 && audio->playingCh4) {
if (when - audio->ch4.lastEvent > (uint32_t) audio->sampleInterval) {
// Back-compat: fake this value
audio->ch4.lastEvent = when - audio->sampleInterval;
}
mTimingSchedule(audio->timing, &audio->ch4Event, when);
}
}