GBA Audio: Decrunchify GB audio

This commit is contained in:
Vicki Pfau 2022-06-15 20:34:06 -07:00
parent 33b3d33da2
commit 6159c5a70b
6 changed files with 125 additions and 50 deletions

View File

@ -80,14 +80,16 @@ struct GBAAudio {
bool enable; bool enable;
size_t samples; size_t samples;
unsigned sampleRate;
GBARegisterSOUNDBIAS soundbias; GBARegisterSOUNDBIAS soundbias;
struct GBAAudioMixer* mixer; struct GBAAudioMixer* mixer;
bool externalMixing; bool externalMixing;
int32_t sampleInterval; int32_t sampleInterval;
int32_t lastSample;
int sampleIndex;
struct mStereoSample currentSamples[GBA_MAX_SAMPLES];
bool forceDisableChA; bool forceDisableChA;
bool forceDisableChB; bool forceDisableChB;
int masterVolume; int masterVolume;
@ -305,6 +307,8 @@ uint32_t GBAAudioReadWaveRAM(struct GBAAudio* audio, int address);
uint32_t GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value); uint32_t GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value);
void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles); void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles);
void GBAAudioSample(struct GBAAudio* audio, int32_t timestamp);
struct GBASerializedState; struct GBASerializedState;
void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state); void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state);
void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state); void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state);

View File

@ -71,7 +71,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | 0x00188 - 0x0018B: Next event * | 0x00188 - 0x0018B: Next event
* 0x0018C - 0x001AB: Audio FIFO 1 * 0x0018C - 0x001AB: Audio FIFO 1
* 0x001AC - 0x001CB: Audio FIFO 2 * 0x001AC - 0x001CB: Audio FIFO 2
* 0x001CC - 0x001DF: Audio miscellaneous state * 0x001CC - 0x001EF: Audio miscellaneous state
* | 0x001CC - 0x001CF: Channel A internal audio samples * | 0x001CC - 0x001CF: Channel A internal audio samples
* | 0x001D0 - 0x001D3: Channel B internal audio samples * | 0x001D0 - 0x001D3: Channel B internal audio samples
* | 0x001D4 - 0x001D7: Next sample * | 0x001D4 - 0x001D7: Next sample
@ -104,9 +104,13 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | bit 3: Is channel 3's memory readable? * | bit 3: Is channel 3's memory readable?
* | bit 4: Skip frame * | bit 4: Skip frame
* | bits 5 - 7: Reserved * | bits 5 - 7: Reserved
* 0x001E0 - 0x001FF: Video miscellaneous state * | 0x001E0 - 0x001E3: Last sample
* | 0x001E0 - 0x001E3: Next event * | 0x001E4 - 0x001E7: Additional audio flags
* | 0x001E4 - 0x001F7: Reserved * | bits 0 - 3: Current sample index
* | 0x001E8 - 0x001EF: Reserved
* 0x001F0 - 0x001FF: Video miscellaneous state
* | 0x001F0 - 0x001F3: Reserved
* | 0x001F4 - 0x001F7: Next event
* | 0x001F8 - 0x001FB: Miscellaneous flags * | 0x001F8 - 0x001FB: Miscellaneous flags
* | 0x001FC - 0x001FF: Frame counter * | 0x001FC - 0x001FF: Frame counter
* 0x00200 - 0x00213: Timer 0 * 0x00200 - 0x00213: Timer 0
@ -227,7 +231,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* 0x00368 - 0x0036F: Reserved (leave zero) * 0x00368 - 0x0036F: Reserved (leave zero)
* 0x00370 - 0x0037F: Audio FIFO A samples * 0x00370 - 0x0037F: Audio FIFO A samples
* 0x00380 - 0x0038F: Audio FIFO B samples * 0x00380 - 0x0038F: Audio FIFO B samples
* 0x00390 - 0x003FF: Reserved (leave zero) * 0x00390 - 0x003CF: Audio rendered samples
* 0x003D0 - 0x003FF: Reserved (leave zero)
* 0x00400 - 0x007FF: I/O memory * 0x00400 - 0x007FF: I/O memory
* 0x00800 - 0x00BFF: Palette * 0x00800 - 0x00BFF: Palette
* 0x00C00 - 0x00FFF: OAM * 0x00C00 - 0x00FFF: OAM
@ -243,6 +248,9 @@ DECL_BITS(GBASerializedAudioFlags, FIFOSamplesB, 2, 3); // Yay legacy?
DECL_BITS(GBASerializedAudioFlags, FIFOInternalSamplesA, 5, 2); DECL_BITS(GBASerializedAudioFlags, FIFOInternalSamplesA, 5, 2);
DECL_BITS(GBASerializedAudioFlags, FIFOSamplesA, 7, 3); DECL_BITS(GBASerializedAudioFlags, FIFOSamplesA, 7, 3);
DECL_BITFIELD(GBASerializedAudioFlags2, uint32_t);
DECL_BITS(GBASerializedAudioFlags2, SampleIndex, 0, 4);
DECL_BITFIELD(GBASerializedVideoFlags, uint32_t); DECL_BITFIELD(GBASerializedVideoFlags, uint32_t);
DECL_BITS(GBASerializedVideoFlags, Mode, 0, 2); DECL_BITS(GBASerializedVideoFlags, Mode, 0, 2);
@ -303,11 +311,14 @@ struct GBASerializedState {
int8_t sampleB; int8_t sampleB;
GBASerializedAudioFlags gbaFlags; GBASerializedAudioFlags gbaFlags;
GBSerializedAudioFlags flags; GBSerializedAudioFlags flags;
int32_t lastSample;
GBASerializedAudioFlags2 gbaFlags2;
int32_t reserved[2];
} audio; } audio;
struct { struct {
int32_t reserved;
int32_t nextEvent; int32_t nextEvent;
int32_t reserved[5];
GBASerializedVideoFlags flags; GBASerializedVideoFlags flags;
uint32_t frameCounter; uint32_t frameCounter;
} video; } video;
@ -384,14 +395,16 @@ struct GBASerializedState {
int32_t biosStall; int32_t biosStall;
uint32_t matrixMappings[16]; uint32_t matrixMappings[16];
uint32_t reservedMatrix[2]; uint32_t reservedMatrix[2];
struct { struct {
int8_t chA[16]; int8_t chA[16];
int8_t chB[16]; int8_t chB[16];
} samples; } samples;
uint32_t reserved[28]; struct mStereoSample currentSamples[16];
uint32_t reserved[12];
uint16_t io[SIZE_IO >> 1]; uint16_t io[SIZE_IO >> 1];
uint16_t pram[SIZE_PALETTE_RAM >> 1]; uint16_t pram[SIZE_PALETTE_RAM >> 1];

View File

@ -11,6 +11,9 @@
#include <mgba/internal/gb/gb.h> #include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/serialize.h> #include <mgba/internal/gb/serialize.h>
#include <mgba/internal/gb/io.h> #include <mgba/internal/gb/io.h>
#ifdef M_CORE_GBA
#include <mgba/internal/gba/audio.h>
#endif
#ifdef __3DS__ #ifdef __3DS__
#define blip_add_delta blip_add_delta_fast #define blip_add_delta blip_add_delta_fast
@ -69,7 +72,6 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAu
audio->timingFactor = 2; audio->timingFactor = 2;
} }
audio->frameEvent.context = audio;
audio->frameEvent.name = "GB Audio Frame Sequencer"; audio->frameEvent.name = "GB Audio Frame Sequencer";
audio->frameEvent.callback = _updateFrame; audio->frameEvent.callback = _updateFrame;
audio->frameEvent.priority = 0x10; audio->frameEvent.priority = 0x10;
@ -85,14 +87,10 @@ void GBAudioDeinit(struct GBAudio* audio) {
} }
void GBAudioReset(struct GBAudio* audio) { void GBAudioReset(struct GBAudio* audio) {
mTimingDeschedule(audio->timing, &audio->frameEvent);
mTimingDeschedule(audio->timing, &audio->sampleEvent); mTimingDeschedule(audio->timing, &audio->sampleEvent);
if (audio->style != GB_AUDIO_GBA) { if (audio->style != GB_AUDIO_GBA) {
mTimingSchedule(audio->timing, &audio->sampleEvent, 0); mTimingSchedule(audio->timing, &audio->sampleEvent, 0);
} }
if (audio->style == GB_AUDIO_GBA) {
mTimingSchedule(audio->timing, &audio->frameEvent, 0);
}
audio->ch1 = (struct GBAudioSquareChannel) { .sweep = { .time = 8 }, .envelope = { .dead = 2 } }; audio->ch1 = (struct GBAudioSquareChannel) { .sweep = { .time = 8 }, .envelope = { .dead = 2 } };
audio->ch2 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } }; audio->ch2 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } };
audio->ch3 = (struct GBAudioWaveChannel) { .bank = 0 }; audio->ch3 = (struct GBAudioWaveChannel) { .bank = 0 };
@ -458,11 +456,12 @@ void GBAudioWriteNR52(struct GBAudio* audio, uint8_t value) {
} }
void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate) { void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct GBAudio* audio = user; #ifdef M_CORE_GBA
GBAudioUpdateFrame(audio); struct GBAAudio* audio = user;
if (audio->style == GB_AUDIO_GBA) { GBAAudioSample(audio, mTimingCurrentTime(timing));
mTimingSchedule(timing, &audio->frameEvent, audio->timingFactor * FRAME_CYCLES - cyclesLate); mTimingSchedule(timing, &audio->psg.frameEvent, audio->psg.timingFactor * FRAME_CYCLES - cyclesLate);
} GBAudioUpdateFrame(&audio->psg);
#endif
} }
void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) {

View File

@ -44,6 +44,7 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA); GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA);
audio->psg.timing = &audio->p->timing; audio->psg.timing = &audio->p->timing;
audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY; audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY;
audio->psg.frameEvent.context = audio;
audio->samples = samples; audio->samples = samples;
// Guess too large; we hang producing extra samples if we guess too low // Guess too large; we hang producing extra samples if we guess too low
blip_set_rates(audio->psg.left, GBA_ARM7TDMI_FREQUENCY, 96000); blip_set_rates(audio->psg.left, GBA_ARM7TDMI_FREQUENCY, 96000);
@ -58,6 +59,8 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
void GBAAudioReset(struct GBAAudio* audio) { void GBAAudioReset(struct GBAAudio* audio) {
GBAudioReset(&audio->psg); GBAudioReset(&audio->psg);
mTimingDeschedule(&audio->p->timing, &audio->psg.frameEvent);
mTimingSchedule(&audio->p->timing, &audio->psg.frameEvent, 0);
mTimingDeschedule(&audio->p->timing, &audio->sampleEvent); mTimingDeschedule(&audio->p->timing, &audio->sampleEvent);
mTimingSchedule(&audio->p->timing, &audio->sampleEvent, 0); mTimingSchedule(&audio->p->timing, &audio->sampleEvent, 0);
audio->chA.dmaSource = 1; audio->chA.dmaSource = 1;
@ -77,11 +80,12 @@ void GBAAudioReset(struct GBAAudio* audio) {
audio->chA.samples[i] = 0; audio->chA.samples[i] = 0;
audio->chB.samples[i] = 0; audio->chB.samples[i] = 0;
} }
audio->sampleRate = 0x8000;
audio->soundbias = 0x200; audio->soundbias = 0x200;
audio->volume = 0; audio->volume = 0;
audio->volumeChA = false; audio->volumeChA = false;
audio->volumeChB = false; audio->volumeChB = false;
audio->lastSample = 0;
audio->sampleIndex = 0;
audio->chARight = false; audio->chARight = false;
audio->chALeft = false; audio->chALeft = false;
audio->chATimer = false; audio->chATimer = false;
@ -89,7 +93,7 @@ void GBAAudioReset(struct GBAAudio* audio) {
audio->chBLeft = false; audio->chBLeft = false;
audio->chBTimer = false; audio->chBTimer = false;
audio->enable = false; audio->enable = false;
audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate; audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / 0x8000;
audio->psg.sampleInterval = audio->sampleInterval; audio->psg.sampleInterval = audio->sampleInterval;
blip_clear(audio->psg.left); blip_clear(audio->psg.left);
@ -141,56 +145,67 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA*
} }
void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR10(&audio->psg, value); GBAudioWriteNR10(&audio->psg, value);
} }
void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR11(&audio->psg, value); GBAudioWriteNR11(&audio->psg, value);
GBAudioWriteNR12(&audio->psg, value >> 8); GBAudioWriteNR12(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR13(&audio->psg, value); GBAudioWriteNR13(&audio->psg, value);
GBAudioWriteNR14(&audio->psg, value >> 8); GBAudioWriteNR14(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR21(&audio->psg, value); GBAudioWriteNR21(&audio->psg, value);
GBAudioWriteNR22(&audio->psg, value >> 8); GBAudioWriteNR22(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR23(&audio->psg, value); GBAudioWriteNR23(&audio->psg, value);
GBAudioWriteNR24(&audio->psg, value >> 8); GBAudioWriteNR24(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
audio->psg.ch3.size = GBAudioRegisterBankGetSize(value); audio->psg.ch3.size = GBAudioRegisterBankGetSize(value);
audio->psg.ch3.bank = GBAudioRegisterBankGetBank(value); audio->psg.ch3.bank = GBAudioRegisterBankGetBank(value);
GBAudioWriteNR30(&audio->psg, value); GBAudioWriteNR30(&audio->psg, value);
} }
void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR31(&audio->psg, value); GBAudioWriteNR31(&audio->psg, value);
audio->psg.ch3.volume = GBAudioRegisterBankVolumeGetVolumeGBA(value >> 8); audio->psg.ch3.volume = GBAudioRegisterBankVolumeGetVolumeGBA(value >> 8);
} }
void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR33(&audio->psg, value); GBAudioWriteNR33(&audio->psg, value);
GBAudioWriteNR34(&audio->psg, value >> 8); GBAudioWriteNR34(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR41(&audio->psg, value); GBAudioWriteNR41(&audio->psg, value);
GBAudioWriteNR42(&audio->psg, value >> 8); GBAudioWriteNR42(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR43(&audio->psg, value); GBAudioWriteNR43(&audio->psg, value);
GBAudioWriteNR44(&audio->psg, value >> 8); GBAudioWriteNR44(&audio->psg, value >> 8);
} }
void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) { void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) {
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing));
GBAudioWriteNR50(&audio->psg, value); GBAudioWriteNR50(&audio->psg, value);
GBAudioWriteNR51(&audio->psg, value >> 8); GBAudioWriteNR51(&audio->psg, value >> 8);
} }
@ -328,17 +343,17 @@ static int _applyBias(struct GBAAudio* audio, int sample) {
return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume * 3) >> 4; return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume * 3) >> 4;
} }
static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { void GBAAudioSample(struct GBAAudio* audio, int32_t timestamp) {
struct GBAAudio* audio = user; timestamp -= audio->lastSample;
int16_t samplesLeft[GBA_MAX_SAMPLES]; timestamp -= audio->sampleIndex * audio->sampleInterval; // TODO: This can break if the interval changes between samples
int16_t samplesRight[GBA_MAX_SAMPLES];
int32_t timestamp = mTimingCurrentTime(&audio->p->timing) - cyclesLate - SAMPLE_INTERVAL; int maxSample = 2 << GBARegisterSOUNDBIASGetResolution(audio->soundbias);
int sample; int sample;
for (sample = 0; sample * audio->sampleInterval < (int32_t) SAMPLE_INTERVAL; ++sample) { for (sample = audio->sampleIndex; timestamp >= audio->sampleInterval && sample < maxSample; ++sample, timestamp -= audio->sampleInterval) {
int16_t sampleLeft = 0; int16_t sampleLeft = 0;
int16_t sampleRight = 0; int16_t sampleRight = 0;
int psgShift = 4 - audio->volume; int psgShift = 4 - audio->volume;
GBAudioRun(&audio->psg, timestamp + (sample + 1) * audio->sampleInterval, 0xF); GBAudioRun(&audio->psg, sample * audio->sampleInterval + audio->lastSample, 0xF);
GBAudioSamplePSG(&audio->psg, &sampleLeft, &sampleRight); GBAudioSamplePSG(&audio->psg, &sampleLeft, &sampleRight);
sampleLeft >>= psgShift; sampleLeft >>= psgShift;
sampleRight >>= psgShift; sampleRight >>= psgShift;
@ -370,21 +385,34 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
sampleLeft = _applyBias(audio, sampleLeft); sampleLeft = _applyBias(audio, sampleLeft);
sampleRight = _applyBias(audio, sampleRight); sampleRight = _applyBias(audio, sampleRight);
samplesLeft[sample] = sampleLeft; audio->currentSamples[sample].left = sampleLeft;
samplesRight[sample] = sampleRight; audio->currentSamples[sample].right = sampleRight;
} }
memset(audio->chA.samples, audio->chA.samples[sample - 1], sizeof(audio->chA.samples)); audio->sampleIndex = sample;
memset(audio->chB.samples, audio->chB.samples[sample - 1], sizeof(audio->chB.samples)); if (sample == maxSample) {
audio->lastSample += SAMPLE_INTERVAL;
audio->sampleIndex = 0;
}
}
static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct GBAAudio* audio = user;
GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing) - cyclesLate);
int samples = 2 << GBARegisterSOUNDBIASGetResolution(audio->soundbias);
int sampleMask = 1 << GBARegisterSOUNDBIASGetResolution(audio->soundbias);
memset(audio->chA.samples, audio->chA.samples[samples - 1], sizeof(audio->chA.samples));
memset(audio->chB.samples, audio->chB.samples[samples - 1], sizeof(audio->chB.samples));
mCoreSyncLockAudio(audio->p->sync); mCoreSyncLockAudio(audio->p->sync);
unsigned produced; unsigned produced;
int32_t sampleSumLeft = 0; int32_t sampleSumLeft = 0;
int32_t sampleSumRight = 0; int32_t sampleSumRight = 0;
int i; int i;
for (i = 0; i < sample; ++i) { for (i = 0; i < samples; ++i) {
int16_t sampleLeft = samplesLeft[i]; int16_t sampleLeft = audio->currentSamples[i].left;
int16_t sampleRight = samplesRight[i]; int16_t sampleRight = audio->currentSamples[i].right;
sampleSumLeft += sampleLeft; sampleSumLeft += sampleLeft;
sampleSumRight += sampleRight; sampleSumRight += sampleRight;
if ((size_t) blip_samples_avail(audio->psg.left) < audio->samples) { if ((size_t) blip_samples_avail(audio->psg.left) < audio->samples) {
@ -399,12 +427,14 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
audio->clock -= CLOCKS_PER_FRAME; audio->clock -= CLOCKS_PER_FRAME;
} }
} }
} // TODO: Post all frames
// TODO: Post all frames if (audio->p->stream && audio->p->stream->postAudioFrame && (i & (sampleMask - 1)) == sampleMask - 1) {
if (audio->p->stream && audio->p->stream->postAudioFrame) { sampleSumLeft /= sampleMask;
sampleSumLeft /= sample; sampleSumRight /= sampleMask;
sampleSumRight /= sample; audio->p->stream->postAudioFrame(audio->p->stream, sampleSumLeft, sampleSumRight);
audio->p->stream->postAudioFrame(audio->p->stream, sampleSumLeft, sampleSumRight); sampleSumLeft = 0;
sampleSumRight = 0;
}
} }
produced = blip_samples_avail(audio->psg.left); produced = blip_samples_avail(audio->psg.left);
bool wait = produced >= audio->samples; bool wait = produced >= audio->samples;
@ -428,9 +458,15 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState*
memcpy(state->samples.chA, audio->chA.samples, sizeof(audio->chA.samples)); memcpy(state->samples.chA, audio->chA.samples, sizeof(audio->chA.samples));
memcpy(state->samples.chB, audio->chB.samples, sizeof(audio->chB.samples)); memcpy(state->samples.chB, audio->chB.samples, sizeof(audio->chB.samples));
size_t i;
for (i = 0; i < GBA_MAX_SAMPLES; ++i) {
STORE_16(audio->currentSamples[i].left, 0, &state->currentSamples[i].left);
STORE_16(audio->currentSamples[i].right, 0, &state->currentSamples[i].right);
}
STORE_32(audio->lastSample, 0, &state->audio.lastSample);
int readA = audio->chA.fifoRead; int readA = audio->chA.fifoRead;
int readB = audio->chB.fifoRead; int readB = audio->chB.fifoRead;
size_t i;
for (i = 0; i < GBA_AUDIO_FIFO_SIZE; ++i) { for (i = 0; i < GBA_AUDIO_FIFO_SIZE; ++i) {
STORE_32(audio->chA.fifo[readA], i << 2, state->audio.fifoA); STORE_32(audio->chA.fifo[readA], i << 2, state->audio.fifoA);
STORE_32(audio->chB.fifo[readB], i << 2, state->audio.fifoB); STORE_32(audio->chB.fifo[readB], i << 2, state->audio.fifoB);
@ -464,6 +500,11 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState*
flags = GBASerializedAudioFlagsSetFIFOInternalSamplesA(flags, audio->chA.internalRemaining); flags = GBASerializedAudioFlagsSetFIFOInternalSamplesA(flags, audio->chA.internalRemaining);
flags = GBASerializedAudioFlagsSetFIFOInternalSamplesB(flags, audio->chB.internalRemaining); flags = GBASerializedAudioFlagsSetFIFOInternalSamplesB(flags, audio->chB.internalRemaining);
STORE_16(flags, 0, &state->audio.gbaFlags); STORE_16(flags, 0, &state->audio.gbaFlags);
GBASerializedAudioFlags2 flags2 = 0;
flags2 = GBASerializedAudioFlags2SetSampleIndex(flags2, audio->sampleIndex);
STORE_32(flags2, 0, &state->audio.gbaFlags2);
STORE_32(audio->sampleEvent.when - mTimingCurrentTime(&audio->p->timing), 0, &state->audio.nextSample); STORE_32(audio->sampleEvent.when - mTimingCurrentTime(&audio->p->timing), 0, &state->audio.nextSample);
} }
@ -475,9 +516,15 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
memcpy(audio->chA.samples, state->samples.chA, sizeof(audio->chA.samples)); memcpy(audio->chA.samples, state->samples.chA, sizeof(audio->chA.samples));
memcpy(audio->chB.samples, state->samples.chB, sizeof(audio->chB.samples)); memcpy(audio->chB.samples, state->samples.chB, sizeof(audio->chB.samples));
size_t i;
for (i = 0; i < GBA_MAX_SAMPLES; ++i) {
LOAD_16(audio->currentSamples[i].left, 0, &state->currentSamples[i].left);
LOAD_16(audio->currentSamples[i].right, 0, &state->currentSamples[i].right);
}
LOAD_32(audio->lastSample, 0, &state->audio.lastSample);
int readA = 0; int readA = 0;
int readB = 0; int readB = 0;
size_t i;
for (i = 0; i < GBA_AUDIO_FIFO_SIZE; ++i) { for (i = 0; i < GBA_AUDIO_FIFO_SIZE; ++i) {
LOAD_32(audio->chA.fifo[readA], i << 2, state->audio.fifoA); LOAD_32(audio->chA.fifo[readA], i << 2, state->audio.fifoA);
LOAD_32(audio->chB.fifo[readB], i << 2, state->audio.fifoB); LOAD_32(audio->chB.fifo[readB], i << 2, state->audio.fifoB);
@ -494,8 +541,15 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
audio->chA.internalRemaining = GBASerializedAudioFlagsGetFIFOInternalSamplesA(flags); audio->chA.internalRemaining = GBASerializedAudioFlagsGetFIFOInternalSamplesA(flags);
audio->chB.internalRemaining = GBASerializedAudioFlagsGetFIFOInternalSamplesB(flags); audio->chB.internalRemaining = GBASerializedAudioFlagsGetFIFOInternalSamplesB(flags);
GBASerializedAudioFlags2 flags2;
LOAD_32(flags2, 0, &state->audio.gbaFlags2);
audio->sampleIndex = GBASerializedAudioFlags2GetSampleIndex(flags2);
uint32_t when; uint32_t when;
LOAD_32(when, 0, &state->audio.nextSample); LOAD_32(when, 0, &state->audio.nextSample);
if (state->versionMagic < 0x01000007) {
audio->lastSample = when - SAMPLE_INTERVAL;
}
mTimingSchedule(&audio->p->timing, &audio->sampleEvent, when); mTimingSchedule(&audio->p->timing, &audio->sampleEvent, when);
} }

View File

@ -15,7 +15,7 @@
#include <fcntl.h> #include <fcntl.h>
MGBA_EXPORT const uint32_t GBASavestateMagic = 0x01000000; MGBA_EXPORT const uint32_t GBASavestateMagic = 0x01000000;
MGBA_EXPORT const uint32_t GBASavestateVersion = 0x00000006; MGBA_EXPORT const uint32_t GBASavestateVersion = 0x00000007;
mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize"); mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize");

View File

@ -377,7 +377,12 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState
break; break;
} }
uint32_t when; uint32_t when;
LOAD_32(when, 0, &state->video.nextEvent); if (state->versionMagic < 0x01000007) {
// This field was moved in v7
LOAD_32(when, 0, &state->audio.lastSample);
} else {
LOAD_32(when, 0, &state->video.nextEvent);
}
mTimingSchedule(&video->p->timing, &video->event, when); mTimingSchedule(&video->p->timing, &video->event, when);
LOAD_16(video->vcount, REG_VCOUNT, state->io); LOAD_16(video->vcount, REG_VCOUNT, state->io);