mirror of https://github.com/mgba-emu/mgba.git
GBA Audio: Sample FIFOs at SOUNDBIAS-set frequency
This commit is contained in:
parent
29dbb55c80
commit
3c0d9f7197
1
CHANGES
1
CHANGES
|
@ -29,6 +29,7 @@ Emulation fixes:
|
|||
- GBA: Fix expected entry point for multiboot ELFs (fixes mgba.io/i/2450)
|
||||
- GBA: Fix booting multiboot ROMs with no JOY entrypoint
|
||||
- GBA Audio: Adjust PSG sampling rate with SOUNDBIAS
|
||||
- GBA Audio: Sample FIFOs at SOUNDBIAS-set frequency
|
||||
- GBA BIOS: Work around IRQ handling hiccup in Mario & Luigi (fixes mgba.io/i/1059)
|
||||
- GBA BIOS: Initial HLE timing estimation of UnLz77 functions (fixes mgba.io/i/2141)
|
||||
- GBA DMA: Fix DMA source direction bits being cleared (fixes mgba.io/i/2410)
|
||||
|
|
|
@ -34,7 +34,7 @@ struct GBAAudioFIFO {
|
|||
uint32_t internalSample;
|
||||
int internalRemaining;
|
||||
int dmaSource;
|
||||
int8_t sample;
|
||||
int8_t samples[8];
|
||||
};
|
||||
|
||||
DECL_BITFIELD(GBARegisterSOUNDCNT_HI, uint16_t);
|
||||
|
|
|
@ -224,7 +224,10 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
|
|||
* 0x00320 - 0x00323: Next IRQ event
|
||||
* 0x00324 - 0x00327: Interruptable BIOS stall cycles
|
||||
* 0x00328 - 0x00367: Matrix memory mapping table
|
||||
* 0x00368 - 0x003FF: Reserved (leave zero)
|
||||
* 0x00368 - 0x0036F: Reserved (leave zero)
|
||||
* 0x00370 - 0x00377: Audio FIFO A samples
|
||||
* 0x00378 - 0x0037F: Audio FIFO B samples
|
||||
* 0x00380 - 0x003FF: Reserved (leave zero)
|
||||
* 0x00400 - 0x007FF: I/O memory
|
||||
* 0x00800 - 0x00BFF: Palette
|
||||
* 0x00C00 - 0x00FFF: OAM
|
||||
|
@ -381,8 +384,14 @@ struct GBASerializedState {
|
|||
int32_t biosStall;
|
||||
|
||||
uint32_t matrixMappings[16];
|
||||
uint32_t reservedMatrix[2];
|
||||
|
||||
uint32_t reserved[38];
|
||||
struct {
|
||||
int8_t chA[8];
|
||||
int8_t chB[8];
|
||||
} samples;
|
||||
|
||||
uint32_t reserved[32];
|
||||
|
||||
uint16_t io[SIZE_IO >> 1];
|
||||
uint16_t pram[SIZE_PALETTE_RAM >> 1];
|
||||
|
|
|
@ -67,13 +67,16 @@ void GBAAudioReset(struct GBAAudio* audio) {
|
|||
audio->chA.internalSample = 0;
|
||||
audio->chA.internalRemaining = 0;
|
||||
memset(audio->chA.fifo, 0, sizeof(audio->chA.fifo));
|
||||
audio->chA.sample = 0;
|
||||
audio->chB.fifoWrite = 0;
|
||||
audio->chB.fifoRead = 0;
|
||||
audio->chB.internalSample = 0;
|
||||
audio->chB.internalRemaining = 0;
|
||||
memset(audio->chB.fifo, 0, sizeof(audio->chB.fifo));
|
||||
audio->chB.sample = 0;
|
||||
int i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
audio->chA.samples[i] = 0;
|
||||
audio->chB.samples[i] = 0;
|
||||
}
|
||||
audio->sampleRate = 0x8000;
|
||||
audio->soundbias = 0x200;
|
||||
audio->volume = 0;
|
||||
|
@ -301,7 +304,17 @@ void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles) {
|
|||
channel->fifoRead = 0;
|
||||
}
|
||||
}
|
||||
channel->sample = channel->internalSample;
|
||||
int32_t until = mTimingUntil(&audio->p->timing, &audio->sampleEvent) - 1;
|
||||
int bits = 1 << GBARegisterSOUNDBIASGetResolution(audio->soundbias);
|
||||
until += 1 << (9 - GBARegisterSOUNDBIASGetResolution(audio->soundbias));
|
||||
until >>= 9 - GBARegisterSOUNDBIASGetResolution(audio->soundbias);
|
||||
int i;
|
||||
for (i = bits - until; i < bits; ++i) {
|
||||
if (i < 0 || i >= bits) {
|
||||
abort();
|
||||
}
|
||||
channel->samples[i] = channel->internalSample;
|
||||
}
|
||||
if (channel->internalRemaining) {
|
||||
channel->internalSample >>= 8;
|
||||
--channel->internalRemaining;
|
||||
|
@ -339,21 +352,21 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
|||
if (!audio->externalMixing) {
|
||||
if (!audio->forceDisableChA) {
|
||||
if (audio->chALeft) {
|
||||
sampleLeft += (audio->chA.sample << 2) >> !audio->volumeChA;
|
||||
sampleLeft += (audio->chA.samples[sample] << 2) >> !audio->volumeChA;
|
||||
}
|
||||
|
||||
if (audio->chARight) {
|
||||
sampleRight += (audio->chA.sample << 2) >> !audio->volumeChA;
|
||||
sampleRight += (audio->chA.samples[sample] << 2) >> !audio->volumeChA;
|
||||
}
|
||||
}
|
||||
|
||||
if (!audio->forceDisableChB) {
|
||||
if (audio->chBLeft) {
|
||||
sampleLeft += (audio->chB.sample << 2) >> !audio->volumeChB;
|
||||
sampleLeft += (audio->chB.samples[sample] << 2) >> !audio->volumeChB;
|
||||
}
|
||||
|
||||
if (audio->chBRight) {
|
||||
sampleRight += (audio->chB.sample << 2) >> !audio->volumeChB;
|
||||
sampleRight += (audio->chB.samples[sample] << 2) >> !audio->volumeChB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -364,12 +377,19 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
|||
samplesRight[sample] = sampleRight;
|
||||
}
|
||||
|
||||
memset(audio->chA.samples, audio->chA.samples[sample - 1], sizeof(audio->chA.samples));
|
||||
memset(audio->chB.samples, audio->chB.samples[sample - 1], sizeof(audio->chB.samples));
|
||||
|
||||
mCoreSyncLockAudio(audio->p->sync);
|
||||
unsigned produced;
|
||||
int32_t sampleSumLeft = 0;
|
||||
int32_t sampleSumRight = 0;
|
||||
int i;
|
||||
for (i = 0; i < sample; ++i) {
|
||||
int16_t sampleLeft = samplesLeft[i];
|
||||
int16_t sampleRight = samplesRight[i];
|
||||
sampleSumLeft += sampleLeft;
|
||||
sampleSumRight += sampleRight;
|
||||
if ((size_t) blip_samples_avail(audio->psg.left) < audio->samples) {
|
||||
blip_add_delta(audio->psg.left, audio->clock, sampleLeft - audio->lastLeft);
|
||||
blip_add_delta(audio->psg.right, audio->clock, sampleRight - audio->lastRight);
|
||||
|
@ -385,7 +405,9 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
|||
}
|
||||
// TODO: Post all frames
|
||||
if (audio->p->stream && audio->p->stream->postAudioFrame) {
|
||||
audio->p->stream->postAudioFrame(audio->p->stream, samplesLeft[sample - 1], samplesRight[sample - 1]);
|
||||
sampleSumLeft /= sample;
|
||||
sampleSumRight /= sample;
|
||||
audio->p->stream->postAudioFrame(audio->p->stream, sampleSumLeft, sampleSumRight);
|
||||
}
|
||||
produced = blip_samples_avail(audio->psg.left);
|
||||
bool wait = produced >= audio->samples;
|
||||
|
@ -406,8 +428,8 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState*
|
|||
|
||||
STORE_32(audio->chA.internalSample, 0, &state->audio.internalA);
|
||||
STORE_32(audio->chB.internalSample, 0, &state->audio.internalB);
|
||||
state->audio.sampleA = audio->chA.sample;
|
||||
state->audio.sampleB = audio->chB.sample;
|
||||
memcpy(state->samples.chA, audio->chA.samples, sizeof(audio->chA.samples));
|
||||
memcpy(state->samples.chB, audio->chB.samples, sizeof(audio->chB.samples));
|
||||
|
||||
int readA = audio->chA.fifoRead;
|
||||
int readB = audio->chB.fifoRead;
|
||||
|
@ -453,8 +475,8 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
|
|||
|
||||
LOAD_32(audio->chA.internalSample, 0, &state->audio.internalA);
|
||||
LOAD_32(audio->chB.internalSample, 0, &state->audio.internalB);
|
||||
audio->chA.sample = state->audio.sampleA;
|
||||
audio->chB.sample = state->audio.sampleB;
|
||||
memcpy(audio->chA.samples, state->samples.chA, sizeof(audio->chA.samples));
|
||||
memcpy(audio->chB.samples, state->samples.chB, sizeof(audio->chB.samples));
|
||||
|
||||
int readA = 0;
|
||||
int readB = 0;
|
||||
|
|
Loading…
Reference in New Issue